diff --git a/main.py b/main.py
index f3dfdc9..ef3df0c 100755
--- a/main.py
+++ b/main.py
@@ -7,6 +7,8 @@
from copy import deepcopy
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
+from urllib.error import HTTPError, URLError
+from urllib.request import Request as UrlRequest, urlopen
from urllib.parse import quote_plus, urlencode
import boto3
@@ -14,7 +16,7 @@
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from PIL import Image
-from pydantic import BaseModel
+from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from starlette.datastructures import URL
from starlette.responses import JSONResponse, RedirectResponse, Response
@@ -120,6 +122,71 @@ class GameOnUtils:
templates = Jinja2Templates(directory=".")
+OPENPATHS_API_BASE = os.environ.get("OPENPATHS_API_BASE", "https://openpaths.io/v1")
+OPENPATHS_API_KEY = os.environ.get("OPENPATHS_API_KEY", "")
+OPENPATHS_ROUTER_MODELS = [
+ model.strip()
+ for model in os.environ.get("OPENPATHS_ROUTER_MODELS", "openai-chat-latest,anthropic-opus-latest").split(",")
+ if model.strip()
+]
+
+
+class MarketingWorkflowRequest(BaseModel):
+ workflow: str
+ target_url: Optional[str] = ""
+ competitor_urls: List[str] = Field(default_factory=list)
+ business_context: Optional[str] = ""
+
+
+def call_openpaths_chat(model: str, messages: List[Dict[str, str]], temperature: float = 0.2) -> str:
+ """
+ Call OpenPaths' OpenAI-compatible endpoint (https://openpaths.io/v1/chat/completions).
+ """
+ if not OPENPATHS_API_KEY:
+ raise HTTPException(status_code=503, detail="OPENPATHS_API_KEY is not configured on the server.")
+
+ endpoint = f"{OPENPATHS_API_BASE.rstrip('/')}/chat/completions"
+ payload = json.dumps(
+ {
+ "model": model,
+ "messages": messages,
+ "temperature": temperature,
+ }
+ ).encode("utf-8")
+
+ req = UrlRequest(
+ endpoint,
+ data=payload,
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {OPENPATHS_API_KEY}",
+ },
+ method="POST",
+ )
+
+ try:
+ with urlopen(req, timeout=40) as resp:
+ body = json.loads(resp.read().decode("utf-8"))
+ except HTTPError as e:
+ error_body = e.read().decode("utf-8", errors="ignore")
+ logger.error(f"OpenPaths HTTP error ({e.code}): {error_body}")
+ raise HTTPException(status_code=502, detail="OpenPaths request failed.")
+ except URLError as e:
+ logger.error(f"OpenPaths network error: {e}")
+ raise HTTPException(status_code=502, detail="Could not reach OpenPaths API.")
+ except Exception as e:
+ logger.error(f"OpenPaths unexpected error: {e}")
+ raise HTTPException(status_code=500, detail="Unexpected OpenPaths error.")
+
+ content = (
+ body.get("choices", [{}])[0]
+ .get("message", {})
+ .get("content", "")
+ )
+ if not content:
+ raise HTTPException(status_code=502, detail="OpenPaths returned an empty response.")
+ return content
+
def get_base_template_vars(request: Request) -> Dict[str, Any]:
"""
@@ -444,7 +511,8 @@ async def tool_page(request: Request, tool_name: str, db: Session = Depends(get_
"tool_keywords": tool_info.get("keywords", ""),
"tool_url": f"/tools/{tool_name}",
"tool_image": tool_info.get("image", ""),
- "tooltemplate": f"templates/tools/{tool_name}.jinja2",
+ "tooltemplate": tool_info.get("template", f"templates/tools/{tool_name}.jinja2"),
+ "tool_workflow_key": tool_info.get("workflow_key", tool_name),
"subscription_required": subscription_required
and subscription_status
and subscription_status.get("subscription_required", False)
@@ -460,6 +528,62 @@ async def tool_page(request: Request, tool_name: str, db: Session = Depends(get_
)
+@app.post("/api/tools/marketing-workflow")
+async def run_marketing_workflow(payload: MarketingWorkflowRequest):
+ workflow_instructions = {
+ "competitor-teardown": (
+ "You are a conversion strategist. Produce: positioning summary, competitor strengths/weaknesses, "
+ "messaging gaps, and a prioritized 7-day action plan."
+ ),
+ "seo-content-gap-finder": (
+ "You are an SEO strategist. Produce: topic clusters, content gaps vs competitors, "
+ "a prioritized publishing roadmap, and suggested briefs."
+ ),
+ "deep-researcher": (
+ "You are a senior research analyst. Produce: key findings, assumptions, risks, "
+ "counterarguments, and next-step experiments."
+ ),
+ "keyword-glossary-explorer": (
+ "You are a search growth strategist. Produce: keyword clusters, search intent buckets, "
+ "glossary page ideas, and internal link opportunities."
+ ),
+ }
+
+ workflow_key = payload.workflow.strip().lower()
+ if workflow_key not in workflow_instructions:
+ raise HTTPException(status_code=400, detail="Unsupported workflow.")
+
+ user_prompt = (
+ f"Workflow: {workflow_key}\n\n"
+ f"Target URL: {payload.target_url or 'N/A'}\n"
+ f"Competitors: {', '.join(payload.competitor_urls) if payload.competitor_urls else 'N/A'}\n\n"
+ f"Context:\n{payload.business_context or 'N/A'}\n\n"
+ "Return markdown with clear headings and bullet points."
+ )
+
+ analyses = []
+ for model in OPENPATHS_ROUTER_MODELS:
+ model_output = call_openpaths_chat(
+ model=model,
+ messages=[
+ {"role": "system", "content": workflow_instructions[workflow_key]},
+ {"role": "user", "content": user_prompt},
+ ],
+ )
+ analyses.append({"model": model, "content": model_output})
+
+ combined_markdown = "\n\n".join(
+ [f"## {analysis['model']}\n\n{analysis['content']}" for analysis in analyses]
+ )
+ return JSONResponse(
+ {
+ "workflow": workflow_key,
+ "analyses": analyses,
+ "combined_markdown": combined_markdown,
+ }
+ )
+
+
@app.get("/subscribe")
async def subscribe(request: Request):
base_vars = get_base_template_vars(request)
@@ -471,6 +595,8 @@ async def subscribe(request: Request):
YOUR_DOMAIN = "https://text-generator.io"
+MONTHLY_SUBSCRIPTION_PRICE_ID = "price_0TMflXDtz2XsjQROwqDwU3Pt" # $9.99/month
+ANNUAL_SUBSCRIPTION_PRICE_ID = "price_0TMfntDtz2XsjQROebse1At5" # $99.99/year
@app.post("/create-checkout-session")
@@ -508,7 +634,7 @@ async def create_checkout_session(
if type == "annual":
line_item: Dict[str, Any] = {
- "price": "price_0RXdd4Dtz2XsjQRO5hYsdfjx", # New annual price ID ($190/year)
+ "price": ANNUAL_SUBSCRIPTION_PRICE_ID,
"quantity": 1,
}
elif type == "self-hosted":
@@ -520,7 +646,7 @@ async def create_checkout_session(
else:
# Default monthly - metered subscription, no quantity
line_item: Dict[str, Any] = {
- "price": "price_0RXdbtDtz2XsjQROW0xgtU8H", # New monthly price ID ($19/month)
+ "price": MONTHLY_SUBSCRIPTION_PRICE_ID,
"quantity": 1,
}
@@ -616,9 +742,9 @@ async def create_checkout_session_embedded(
# Set up pricing based on subscription type
if subscription_type and subscription_type == "annual":
- subscription_price = "price_0RXdd4Dtz2XsjQRO5hYsdfjx" # $190/year
+ subscription_price = ANNUAL_SUBSCRIPTION_PRICE_ID
else:
- subscription_price = "price_0RXdbtDtz2XsjQROW0xgtU8H" # $19/month
+ subscription_price = MONTHLY_SUBSCRIPTION_PRICE_ID
success_url = YOUR_DOMAIN + "/playground"
diff --git a/questions/tool_fixtures.py b/questions/tool_fixtures.py
index 6033057..efaf0c6 100755
--- a/questions/tool_fixtures.py
+++ b/questions/tool_fixtures.py
@@ -84,4 +84,40 @@
},
},
},
+ "competitor-teardown": {
+ "name": "Competitor Teardown",
+ "description": "Analyze competing pages, uncover positioning gaps, and get actionable improvements.",
+ "url": "/tools/competitor-teardown",
+ "image": "img/prompt-optimizer.webp",
+ "keywords": "competitor analysis, positioning, conversion copy, landing page teardown",
+ "template": "static/templates/tools/marketing-workflow-tool.jinja2",
+ "workflow_key": "competitor-teardown",
+ },
+ "seo-content-gap-finder": {
+ "name": "SEO Content Gap Finder",
+ "description": "Compare your site with competitors and generate a prioritized content gap plan.",
+ "url": "/tools/seo-content-gap-finder",
+ "image": "img/prompt-optimizer.webp",
+ "keywords": "seo content gap, topic clusters, content briefs, search growth",
+ "template": "static/templates/tools/marketing-workflow-tool.jinja2",
+ "workflow_key": "seo-content-gap-finder",
+ },
+ "deep-researcher": {
+ "name": "Deep Researcher",
+ "description": "Build structured research summaries with risks, opportunities, and next actions.",
+ "url": "/tools/deep-researcher",
+ "image": "img/prompt-optimizer.webp",
+ "keywords": "deep research, market analysis, synthesis, strategic insights",
+ "template": "static/templates/tools/marketing-workflow-tool.jinja2",
+ "workflow_key": "deep-researcher",
+ },
+ "keyword-glossary-explorer": {
+ "name": "Keyword & Glossary Explorer",
+ "description": "Turn a niche into keyword clusters and plain-English glossary pages you can publish.",
+ "url": "/tools/keyword-glossary-explorer",
+ "image": "img/prompt-optimizer.webp",
+ "keywords": "keyword research, glossary pages, long-tail seo, topical authority",
+ "template": "static/templates/tools/marketing-workflow-tool.jinja2",
+ "workflow_key": "keyword-glossary-explorer",
+ },
}
diff --git a/static/css/checkout-dialog.css b/static/css/checkout-dialog.css
index f0a888e..b60705c 100755
--- a/static/css/checkout-dialog.css
+++ b/static/css/checkout-dialog.css
@@ -76,7 +76,42 @@
font-size: 28px;
font-weight: 600;
color: #333;
- margin: 0 0 16px 0;
+ margin: 0;
+}
+
+.checkout-dialog-subtitle {
+ margin: 10px 0 0;
+ color: #666;
+ font-size: 14px;
+}
+
+.checkout-price-highlight {
+ display: inline-flex;
+ align-items: baseline;
+ gap: 8px;
+ margin-top: 14px;
+ padding: 10px 14px;
+ border-radius: 999px;
+ background: #f3f7ff;
+ border: 1px solid #d9e6ff;
+}
+
+.checkout-price-value {
+ color: #1155cc;
+ font-size: 34px;
+ font-weight: 800;
+ line-height: 1;
+}
+
+.checkout-price-period {
+ color: #1155cc;
+ font-weight: 700;
+}
+
+.checkout-price-note {
+ color: #5d6f92;
+ font-size: 12px;
+ font-weight: 600;
}
.checkout-pricing-toggle {
@@ -84,6 +119,7 @@
gap: 16px;
justify-content: center;
flex-wrap: wrap;
+ margin-top: 14px;
}
.checkout-toggle-label {
@@ -104,6 +140,10 @@
margin-right: 8px;
}
+.checkout-toggle-text {
+ font-weight: 600;
+}
+
.checkout-toggle-label input[type="radio"]:checked + .checkout-toggle-text {
color: #1a73e8;
font-weight: 600;
@@ -141,6 +181,30 @@
margin-top: 2px;
}
+.checkout-offer-chooser {
+ margin-top: 14px;
+ display: flex;
+ justify-content: center;
+ gap: 8px;
+}
+
+.checkout-offer-btn {
+ border: 1px solid #d2d9e6;
+ background: #fff;
+ color: #334155;
+ border-radius: 999px;
+ padding: 8px 14px;
+ font-size: 13px;
+ font-weight: 600;
+ cursor: pointer;
+}
+
+.checkout-offer-btn.is-active {
+ border-color: #1a73e8;
+ background: #e8f0fe;
+ color: #0d47a1;
+}
+
.checkout-dialog-body {
padding: 32px;
}
@@ -209,6 +273,42 @@
background: #1557b0;
}
+.checkout-btn-secondary {
+ background: #eef2f7;
+ color: #1f2937;
+}
+
+.checkout-btn-secondary:hover {
+ background: #dde4ee;
+}
+
+.checkout-credits-panel {
+ border: 1px solid #e2e8f0;
+ background: #f8fafc;
+ border-radius: 10px;
+ padding: 18px;
+ text-align: center;
+}
+
+.checkout-credits-panel h3 {
+ margin: 0 0 8px;
+ font-size: 20px;
+ color: #1e293b;
+}
+
+.checkout-credits-panel p {
+ margin: 0;
+ color: #475569;
+}
+
+.checkout-credits-actions {
+ margin-top: 14px;
+ display: flex;
+ gap: 10px;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
/* Mobile responsiveness */
@media (max-width: 768px) {
.checkout-dialog-content {
@@ -226,6 +326,10 @@
.checkout-dialog-title {
font-size: 24px;
}
+
+ .checkout-price-value {
+ font-size: 30px;
+ }
.checkout-pricing-toggle {
flex-direction: column;
@@ -261,4 +365,4 @@
.StripeElement--webkit-autofill {
background-color: #fefde5 !important;
-}
\ No newline at end of file
+}
diff --git a/static/js/checkout-dialog.js b/static/js/checkout-dialog.js
index c5ebccf..9dae2f5 100755
--- a/static/js/checkout-dialog.js
+++ b/static/js/checkout-dialog.js
@@ -1,4 +1,10 @@
// Checkout Dialog with Embedded Stripe Checkout
+const CHECKOUT_PRICING = {
+ monthly: '$9.99',
+ annual: '$99.99',
+ savingsLabel: 'save 17%',
+};
+
class CheckoutDialog {
constructor() {
this.modal = null;
@@ -8,6 +14,8 @@ class CheckoutDialog {
this.elements = null;
this.embeddedCheckout = null;
this.subscriptionType = 'monthly';
+ this.offerType = 'plan';
+ this.allowCreditChoice = window.location.pathname === '/playground';
this.init();
}
@@ -46,9 +54,37 @@ class CheckoutDialog {
+
+
API credits
+
Need pay-as-you-go API credits instead of a recurring plan?
+
+
@@ -88,6 +124,17 @@ class CheckoutDialog {
}
}
});
+
+ document.addEventListener('click', (e) => {
+ const offerBtn = e.target.closest('.checkout-offer-btn');
+ if (offerBtn) {
+ this.setOfferType(offerBtn.dataset.offer || 'plan');
+ }
+
+ if (e.target.id === 'checkout-switch-plan-btn') {
+ this.setOfferType('plan');
+ }
+ });
}
async getCurrentUser() {
@@ -106,6 +153,11 @@ class CheckoutDialog {
}
async loadCheckout() {
+ if (this.offerType === 'credits') {
+ this.renderCreditsState();
+ return;
+ }
+
const user = await this.getCurrentUser();
if (!user) {
this.showError('Please log in to subscribe');
@@ -169,12 +221,54 @@ class CheckoutDialog {
`;
}
+ renderCreditsState() {
+ const checkoutContainer = document.getElementById('checkout-container');
+ if (checkoutContainer) {
+ checkoutContainer.innerHTML = '';
+ }
+
+ const creditsPanel = document.getElementById('checkout-credits-panel');
+ if (creditsPanel) {
+ creditsPanel.style.display = 'block';
+ }
+ }
+
+ setOfferType(offerType = 'plan') {
+ this.offerType = offerType;
+ const buttons = document.querySelectorAll('.checkout-offer-btn');
+ buttons.forEach((btn) => {
+ btn.classList.toggle('is-active', btn.dataset.offer === offerType);
+ });
+
+ const creditsPanel = document.getElementById('checkout-credits-panel');
+ if (creditsPanel) {
+ creditsPanel.style.display = offerType === 'credits' ? 'block' : 'none';
+ }
+
+ const checkoutContainer = document.getElementById('checkout-container');
+ if (checkoutContainer) {
+ checkoutContainer.style.display = offerType === 'credits' ? 'none' : 'block';
+ }
+
+ if (this.isOpen && offerType === 'plan') {
+ this.loadCheckout();
+ } else if (this.isOpen && offerType === 'credits') {
+ this.renderCreditsState();
+ }
+ }
+
async show() {
if (this.modal) {
+ const offerChooser = document.getElementById('checkout-offer-chooser');
+ if (offerChooser) {
+ offerChooser.style.display = this.allowCreditChoice ? 'flex' : 'none';
+ }
+
this.modal.style.display = 'flex';
this.modal.classList.add('show');
this.isOpen = true;
document.body.style.overflow = 'hidden';
+ this.setOfferType(this.allowCreditChoice ? this.offerType : 'plan');
// Load checkout when modal is shown
await this.loadCheckout();
@@ -231,6 +325,7 @@ async function showCheckoutDialog(subscriptionType = 'monthly') {
}
}
checkoutDialog.subscriptionType = subscriptionType;
+ checkoutDialog.offerType = window.location.pathname === '/playground' ? checkoutDialog.offerType : 'plan';
// Update radio button selection
const radioBtn = document.querySelector(`input[name="pricing"][value="${subscriptionType}"]`);
if (radioBtn) {
@@ -239,7 +334,9 @@ async function showCheckoutDialog(subscriptionType = 'monthly') {
await checkoutDialog.show();
}
+window.showCheckoutDialog = showCheckoutDialog;
+
// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = { CheckoutDialog, checkoutDialog, showCheckoutDialog };
-}
\ No newline at end of file
+}
diff --git a/static/js/marketing-workflow-tool.js b/static/js/marketing-workflow-tool.js
new file mode 100644
index 0000000..6894342
--- /dev/null
+++ b/static/js/marketing-workflow-tool.js
@@ -0,0 +1,65 @@
+(function () {
+ const root = document.getElementById('marketing-workflow-tool');
+ if (!root) return;
+
+ const workflow = root.dataset.workflow || '';
+ const runBtn = document.getElementById('run-workflow-btn');
+ const status = document.getElementById('workflow-status');
+ const output = document.getElementById('workflow-output');
+ const outputText = document.getElementById('workflow-output-text');
+
+ const targetUrlInput = document.getElementById('tool-target-url');
+ const competitorsInput = document.getElementById('tool-competitors');
+ const contextInput = document.getElementById('tool-context');
+
+ function setStatus(text, isError) {
+ if (!status) return;
+ status.textContent = text || '';
+ status.style.color = isError ? '#d32f2f' : '#666';
+ }
+
+ async function runWorkflow() {
+ const targetUrl = targetUrlInput ? targetUrlInput.value.trim() : '';
+ const competitors = (competitorsInput ? competitorsInput.value : '')
+ .split('\n')
+ .map((v) => v.trim())
+ .filter(Boolean);
+ const context = contextInput ? contextInput.value.trim() : '';
+
+ setStatus('Running analysis...', false);
+ if (runBtn) runBtn.disabled = true;
+
+ try {
+ const response = await fetch('/api/tools/marketing-workflow', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ workflow,
+ target_url: targetUrl,
+ competitor_urls: competitors,
+ business_context: context
+ })
+ });
+
+ const data = await response.json();
+ if (!response.ok) {
+ throw new Error(data.detail || data.error || 'Workflow request failed');
+ }
+
+ if (output && outputText) {
+ outputText.textContent = data.combined_markdown || 'No output received.';
+ output.style.display = 'block';
+ }
+ setStatus(`Done (${(data.analyses || []).length} model(s))`, false);
+ } catch (error) {
+ console.error('Workflow tool error:', error);
+ setStatus(error.message || 'Failed to run workflow', true);
+ } finally {
+ if (runBtn) runBtn.disabled = false;
+ }
+ }
+
+ if (runBtn) {
+ runBtn.addEventListener('click', runWorkflow);
+ }
+})();
diff --git a/static/js/subscription-modal.js b/static/js/subscription-modal.js
index 0e818cd..5088072 100755
--- a/static/js/subscription-modal.js
+++ b/static/js/subscription-modal.js
@@ -1,5 +1,11 @@
// Subscription Modal JavaScript
if (typeof window.SubscriptionModal === 'undefined') {
+const SUBSCRIPTION_MODAL_PRICING = {
+ monthly: '$9.99/mo',
+ annual: '$99.99/year',
+ savingsLabel: 'save 17%',
+};
+
window.SubscriptionModal = class SubscriptionModal {
constructor() {
this.modal = null;
@@ -40,8 +46,8 @@ window.SubscriptionModal = class SubscriptionModal {
-
$19.00
-
per month
+
${SUBSCRIPTION_MODAL_PRICING.monthly}
+
or ${SUBSCRIPTION_MODAL_PRICING.annual} (${SUBSCRIPTION_MODAL_PRICING.savingsLabel})
@@ -84,7 +90,8 @@ window.SubscriptionModal = class SubscriptionModal {
-
Subscribe Now
+
+
@@ -318,6 +325,36 @@ window.SubscriptionModal = class SubscriptionModal {
this.close();
}
});
+
+ document.addEventListener('click', async (e) => {
+ const actionButton = e.target.closest('[data-subscription-action]');
+ if (!actionButton) {
+ return;
+ }
+
+ const action = actionButton.dataset.subscriptionAction;
+ if (action === 'plan') {
+ this.close();
+ if (window.showCheckoutDialog) {
+ await window.showCheckoutDialog('monthly');
+ } else {
+ window.location.href = '/subscribe';
+ }
+ return;
+ }
+
+ if (action === 'credits') {
+ this.close();
+ if (window.showCheckoutDialog) {
+ if (window.checkoutDialog) {
+ window.checkoutDialog.offerType = 'credits';
+ }
+ await window.showCheckoutDialog('monthly');
+ } else {
+ window.location.href = '/contact';
+ }
+ }
+ });
}
async checkSubscription() {
diff --git a/static/js/unlimited-ai-modal.js b/static/js/unlimited-ai-modal.js
index 59808a9..74aa090 100755
--- a/static/js/unlimited-ai-modal.js
+++ b/static/js/unlimited-ai-modal.js
@@ -1,5 +1,10 @@
// Unlimited AI Offerings Modal JavaScript
if (typeof window.UnlimitedAIModal === 'undefined') {
+const UNLIMITED_AI_PRICING = {
+ monthly: '$9.99 USD',
+ period: 'Per month',
+};
+
window.UnlimitedAIModal = class UnlimitedAIModal {
constructor() {
this.modal = null;
@@ -39,8 +44,8 @@ window.UnlimitedAIModal = class UnlimitedAIModal {
-
$19.00 USD
-
Monthly
+
${UNLIMITED_AI_PRICING.monthly}
+
${UNLIMITED_AI_PRICING.period}
@@ -369,4 +374,4 @@ if (typeof window.unlimitedAIModal === 'undefined') {
// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = { UnlimitedAIModal, unlimitedAIModal, showUnlimitedAIModal };
-}
\ No newline at end of file
+}
diff --git a/static/templates/ai-text-editor.jinja2 b/static/templates/ai-text-editor.jinja2
index 77e0fa4..3c2e28b 100755
--- a/static/templates/ai-text-editor.jinja2
+++ b/static/templates/ai-text-editor.jinja2
@@ -93,8 +93,22 @@
/* Responsive styling */
@media (max-width: 768px) {
+ .tgdocs-main {
+ overflow-x: hidden;
+ }
+
.tgdocs-sidebar {
- width: 200px;
+ width: 100%;
+ max-width: 100vw;
+ border-right: none;
+ }
+
+ .tgdocs-sidebar-header {
+ padding: 12px 16px;
+ }
+
+ .tgdocs-document-item {
+ padding: 12px 16px;
}
.tgdocs-toolbar {
@@ -165,4 +179,4 @@
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/static/templates/shared/index.jinja2 b/static/templates/shared/index.jinja2
index 5058205..3aeb39e 100755
--- a/static/templates/shared/index.jinja2
+++ b/static/templates/shared/index.jinja2
@@ -77,6 +77,30 @@
Image Captioning AI
Extract useful insight from images with fast multimodal analysis suited for real customer workflows.
+
+
+ travel_explore
+ Competitor Teardown
+ Audit competing pages and get a prioritized list of positioning and conversion opportunities.
+
+
+
+ find_in_page
+ SEO Content Gap Finder
+ Find missing topics, prioritize content opportunities, and build practical publishing roadmaps.
+
+
+
+ menu_book
+ Keyword & Glossary Explorer
+ Generate keyword clusters and glossary plans that improve long-tail topical coverage.
+
+
+
+ psychology_alt
+ Deep Researcher
+ Synthesize complex topics into clear findings, risks, and next-step recommendations.
+
diff --git a/static/templates/shared/subscribe.jinja2 b/static/templates/shared/subscribe.jinja2
index 062d9b9..f8e676f 100755
--- a/static/templates/shared/subscribe.jinja2
+++ b/static/templates/shared/subscribe.jinja2
@@ -96,12 +96,12 @@ window.addEventListener('load', function() {
function updatePricing() {
if ($('.subscription-toggle').is(':checked')) {
$('.subscription-period').text('Annually');
- $('.money-amount').text('$190.00 USD');
+ $('.money-amount').text('$99.99 USD');
$('input[name="type"]').val('annual');
$('.discount-chip').show();
} else {
$('.subscription-period').text('Monthly');
- $('.money-amount').text('$19.00 USD');
+ $('.money-amount').text('$9.99 USD');
$('input[name="type"]').val('monthly');
$('.discount-chip').hide();
}
@@ -187,7 +187,7 @@ window.addEventListener('load', function() {
">cloud
Cloud Text Generator
-
$190.00 USD Annually
+
$99.99 USD Annually