diff --git a/links/mini_apps_views.py b/links/mini_apps_views.py
index 97f8ab0..c9d1286 100644
--- a/links/mini_apps_views.py
+++ b/links/mini_apps_views.py
@@ -19,44 +19,19 @@ class MiniAppsListView(TemplateView):
'color': '#3498db'
},
{
+ 'name': 'TTS (Text-to-Speech)',
+ 'description': 'Convert any text or markdown content to high-quality speech audio.',
+ 'url': 'mini-apps-tts',
+ 'thumbnail': 'https://images.unsplash.com/photo-1589254065878-42c9da997008?w=400&h=300&fit=crop',
+ 'icon': 'fas fa-volume-up',
+ 'color': '#8e44ad'
+ },{
'name': 'Weather Dashboard',
'description': 'Real-time weather information with beautiful visualizations and forecasts.',
'url': '#',
'thumbnail': 'https://images.unsplash.com/photo-1504608524841-42fe6f032b4b?w=400&h=300&fit=crop',
'icon': 'fas fa-cloud-sun',
'color': '#e74c3c'
- },
- {
- 'name': 'Music Player',
- 'description': 'Stream and organize your favorite music with an elegant interface.',
- 'url': '#',
- 'thumbnail': 'https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?w=400&h=300&fit=crop',
- 'icon': 'fas fa-music',
- 'color': '#9b59b6'
- },
- {
- 'name': 'Task Manager',
- 'description': 'Organize your tasks and boost productivity with smart scheduling.',
- 'url': '#',
- 'thumbnail': 'https://images.unsplash.com/photo-1484480974693-6ca0a78fb36b?w=400&h=300&fit=crop',
- 'icon': 'fas fa-tasks',
- 'color': '#2ecc71'
- },
- {
- 'name': 'Code Editor',
- 'description': 'A lightweight code editor with syntax highlighting and themes.',
- 'url': '#',
- 'thumbnail': 'https://images.unsplash.com/photo-1461749280684-dccba630e2f6?w=400&h=300&fit=crop',
- 'icon': 'fas fa-code',
- 'color': '#f39c12'
- },
- {
- 'name': 'Calculator',
- 'description': 'Scientific calculator with advanced mathematical functions.',
- 'url': '#',
- 'thumbnail': 'https://images.unsplash.com/photo-1611224923853-80b023f02d71?w=400&h=300&fit=crop',
- 'icon': 'fas fa-calculator',
- 'color': '#1abc9c'
}
]
@@ -71,3 +46,12 @@ class ImageGalleryView(TemplateView):
context = super().get_context_data(**kwargs)
# Add any context data needed for the image gallery
return context
+
+
+class TTSView(TemplateView):
+ template_name = 'links/mini_apps/tts.html'
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['page_title'] = 'Text-to-Speech'
+ return context
diff --git a/links/templates/links/mini_apps/tts.html b/links/templates/links/mini_apps/tts.html
new file mode 100644
index 0000000..b9dac46
--- /dev/null
+++ b/links/templates/links/mini_apps/tts.html
@@ -0,0 +1,783 @@
+{% extends 'base.html' %}
+{% load i18n %}
+{% load static %}
+
+{% block title %}{% trans "Text-to-Speech" %} - {% trans "Mini Apps" %}{% endblock %}
+
+{% block extra_css %}
+
+{% endblock %}
+
+{% block content %}
+
+
+
+
+
+
+
+
+
+
+
{% trans "Audio Player" %}
+
{% trans "Ready" %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0:00 / 0:00
+
+
+
+
+
+{% endblock %}
+
+{% block extra_js %}
+
+{% endblock %}
diff --git a/links/urls.py b/links/urls.py
index 9f8605a..dcc6d34 100644
--- a/links/urls.py
+++ b/links/urls.py
@@ -51,6 +51,10 @@ urlpatterns = [
# Mini Apps
path('ui/mini-apps/', mini_apps_views.MiniAppsListView.as_view(), name='mini-apps-list'),
path('ui/mini-apps/image-gallery/', mini_apps_views.ImageGalleryView.as_view(), name='mini-apps-image-gallery'),
+ path('ui/mini-apps/tts/', mini_apps_views.TTSView.as_view(), name='mini-apps-tts'),
+
+ # TTS API
+ path('ui/tts-api/', views.generate_tts_api, name='tts-api'),
# API Documentation
path('ui/api-docs/',
diff --git a/links/views.py b/links/views.py
index 525fd5d..c1e569c 100644
--- a/links/views.py
+++ b/links/views.py
@@ -93,7 +93,7 @@ class LinkListView(ListView):
# Add pinned mini apps with random colors
mini_apps = [
{'name': 'Image Gallery', 'description': 'Browse Images', 'url': 'mini-apps-image-gallery'},
- {'name': 'Coming Soon', 'description': 'New App', 'url': '#'},
+ {'name': 'TTS', 'description': 'Convert text to speech', 'url': 'mini-apps-tts'},
{'name': 'Coming Soon', 'description': 'New App', 'url': '#'}
]
context['mini_apps'] = [
@@ -543,6 +543,50 @@ def generate_tts(request, post_id):
except Exception as e:
return JsonResponse({'error': f'Server error: {str(e)}'}, status=500)
+@require_http_methods(["POST"])
+def generate_tts_api(request):
+ """General TTS API that accepts text content"""
+ try:
+ import json
+
+ # Get text from request body
+ if request.content_type == 'application/json':
+ data = json.loads(request.body)
+ text_content = data.get('text', '')
+ else:
+ text_content = request.POST.get('text', '')
+
+ if not text_content.strip():
+ return JsonResponse({'error': 'No text content provided'}, status=400)
+
+ # Clean the text content - remove markdown and HTML
+ clean_text = clean_text_for_tts(text_content)
+
+ if not clean_text.strip():
+ return JsonResponse({'error': 'No valid text content to convert'}, status=400)
+
+ # Call TTS API
+ import urllib.parse
+ encoded_text = urllib.parse.quote(clean_text)
+ tts_url = f"https://home-tts.junv.workers.dev/tts?text={encoded_text}&haha=hahaJunv"
+
+ try:
+ response = requests.get(tts_url, timeout=30)
+ response.raise_for_status()
+
+ # Return the audio file
+ audio_response = HttpResponse(response.content, content_type='audio/mpeg')
+ audio_response['Content-Disposition'] = f'inline; filename="tts_audio.mp3"'
+ return audio_response
+
+ except requests.RequestException as e:
+ return JsonResponse({'error': f'TTS service error: {str(e)}'}, status=500)
+
+ except json.JSONDecodeError:
+ return JsonResponse({'error': 'Invalid JSON data'}, status=400)
+ except Exception as e:
+ return JsonResponse({'error': f'Server error: {str(e)}'}, status=500)
+
def clean_text_for_tts(content):
"""Clean markdown and HTML from text for TTS"""
# Convert markdown to HTML first