|
|
@@ -23,6 +23,9 @@
|
|
|
auto-height
|
|
|
/>
|
|
|
<view class="input-actions">
|
|
|
+ <button class="action-btn ai-btn" @click="showAIModal">
|
|
|
+ <text>🤖 AI 生成</text>
|
|
|
+ </button>
|
|
|
<button class="action-btn" @click="clearText">清空</button>
|
|
|
<button class="action-btn" @click="pasteText">粘贴</button>
|
|
|
</view>
|
|
|
@@ -101,6 +104,37 @@
|
|
|
<text class="btn-text">{{ generating ? '生成中...' : '生成音频' }}</text>
|
|
|
</button>
|
|
|
</view>
|
|
|
+
|
|
|
+ <!-- AI 生成弹窗 -->
|
|
|
+ <view v-if="showAiModal" class="ai-modal-mask" @click="closeAiModal">
|
|
|
+ <view class="ai-modal" @click.stop>
|
|
|
+ <view class="ai-modal-header">
|
|
|
+ <text class="ai-modal-title">🤖 AI 智能生成</text>
|
|
|
+ <text class="ai-modal-close" @click="closeAiModal">×</text>
|
|
|
+ </view>
|
|
|
+ <view class="ai-modal-content">
|
|
|
+ <textarea
|
|
|
+ v-model="aiPrompt"
|
|
|
+ class="ai-prompt-input"
|
|
|
+ placeholder="输入你想了解的内容,例如:计算机原理是什么?什么是人工智能?"
|
|
|
+ :maxlength="500"
|
|
|
+ />
|
|
|
+ <view class="ai-prompt-hint">
|
|
|
+ <text>AI 将根据你的输入生成相关文本,可直接用于生成音频</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="ai-modal-footer">
|
|
|
+ <button class="ai-cancel-btn" @click="closeAiModal">取消</button>
|
|
|
+ <button
|
|
|
+ class="ai-confirm-btn"
|
|
|
+ :disabled="!aiPrompt.trim() || aiGenerating"
|
|
|
+ @click="handleAIGenerate"
|
|
|
+ >
|
|
|
+ <text>{{ aiGenerating ? '生成中...' : '生成文本' }}</text>
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
@@ -108,6 +142,7 @@
|
|
|
import { ref, computed, onMounted } from 'vue';
|
|
|
import { useUserStore } from '../../store/user';
|
|
|
import { useAudioStore } from '../../store/audio';
|
|
|
+import { post } from '../../utils/request';
|
|
|
import type { VoiceParams } from '../../types';
|
|
|
|
|
|
const userStore = useUserStore();
|
|
|
@@ -122,6 +157,9 @@ const voiceParams = ref<VoiceParams>({
|
|
|
volume: 50,
|
|
|
});
|
|
|
const generating = ref(false);
|
|
|
+const aiGenerating = ref(false);
|
|
|
+const aiPrompt = ref('');
|
|
|
+const showAiModal = ref(false);
|
|
|
|
|
|
// 计算属性
|
|
|
const canGenerate = computed(() => {
|
|
|
@@ -146,6 +184,46 @@ async function pasteText() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// AI 生成文本
|
|
|
+async function handleAIGenerate() {
|
|
|
+ if (!aiPrompt.value.trim()) {
|
|
|
+ uni.showToast({ title: '请输入想了解的内容', icon: 'none' });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ aiGenerating.value = true;
|
|
|
+ try {
|
|
|
+ const result = await post<{ text: string }>('/ai/generate', {
|
|
|
+ prompt: aiPrompt.value,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 将生成的文本填充到输入框
|
|
|
+ text.value = result.text;
|
|
|
+ aiPrompt.value = '';
|
|
|
+
|
|
|
+ // 关闭弹窗
|
|
|
+ showAiModal.value = false;
|
|
|
+
|
|
|
+ uni.showToast({ title: '已生成文本', icon: 'success' });
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('AI 生成失败:', error);
|
|
|
+ uni.showToast({ title: error.message || 'AI 生成失败', icon: 'none' });
|
|
|
+ } finally {
|
|
|
+ aiGenerating.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 显示 AI 生成弹窗
|
|
|
+function showAIModal() {
|
|
|
+ aiPrompt.value = '';
|
|
|
+ showAiModal.value = true;
|
|
|
+}
|
|
|
+
|
|
|
+// 关闭 AI 生成弹窗
|
|
|
+function closeAiModal() {
|
|
|
+ showAiModal.value = false;
|
|
|
+}
|
|
|
+
|
|
|
// 生成音频
|
|
|
async function handleGenerate() {
|
|
|
if (!canGenerate.value) return;
|
|
|
@@ -365,4 +443,112 @@ async function handleGenerate() {
|
|
|
font-weight: 600;
|
|
|
color: #ffffff;
|
|
|
}
|
|
|
+
|
|
|
+/* AI 弹窗样式 */
|
|
|
+.ai-modal-mask {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
+ z-index: 1000;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 32rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-modal {
|
|
|
+ width: 100%;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-modal-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 32rpx;
|
|
|
+ border-bottom: 1rpx solid #f3f4f6;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-modal-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1f2937;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-modal-close {
|
|
|
+ font-size: 48rpx;
|
|
|
+ color: #9ca3af;
|
|
|
+ line-height: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-modal-content {
|
|
|
+ padding: 32rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-prompt-input {
|
|
|
+ width: 100%;
|
|
|
+ height: 200rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+ background: #f9fafb;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #1f2937;
|
|
|
+ line-height: 1.6;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-prompt-hint {
|
|
|
+ margin-top: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-prompt-hint text {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #9ca3af;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-modal-footer {
|
|
|
+ display: flex;
|
|
|
+ gap: 24rpx;
|
|
|
+ padding: 32rpx;
|
|
|
+ border-top: 1rpx solid #f3f4f6;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-cancel-btn,
|
|
|
+.ai-confirm-btn {
|
|
|
+ flex: 1;
|
|
|
+ height: 80rpx;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-cancel-btn {
|
|
|
+ background: #f3f4f6;
|
|
|
+ color: #6b7280;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-confirm-btn {
|
|
|
+ background: linear-gradient(135deg, #4f46e5 0%, #818cf8 100%);
|
|
|
+ color: #ffffff;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-confirm-btn[disabled] {
|
|
|
+ background: #e5e7eb;
|
|
|
+}
|
|
|
+
|
|
|
+.ai-btn {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8rpx;
|
|
|
+}
|
|
|
</style>
|