优化数据

This commit is contained in:
rjb
2025-10-07 00:58:53 +08:00
parent 690dd42adc
commit 3ebcb77ca9
23 changed files with 13031 additions and 31 deletions

View File

@@ -1,3 +1,7 @@
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from src.flask_prompt_master import create_app, db
from src.flask_prompt_master.models import PromptTemplate
import pymysql
@@ -3622,22 +3626,42 @@ templates = [
}
]
def init_db():
"""初始化数据库保留现有user和prompt表数据"""
def init_db(database_type='local'):
"""
初始化数据库,支持本地和腾讯云数据库
Args:
database_type (str): 数据库类型,可选 'local''tencent'
"""
app = create_app()
with app.app_context():
try:
# 连接数据库
conn = pymysql.connect(
host='localhost',
user='root',
password='123456',
database='food_db',
charset='utf8mb4'
)
# 根据数据库类型选择连接配置
if database_type == 'tencent':
# 腾讯云数据库配置
conn = pymysql.connect(
host='gz-cynosdbmysql-grp-d26pzce5.sql.tencentcdb.com',
port=24936,
user='root',
password='!Rjb12191',
database='pro_db',
charset='utf8mb4'
)
print("🔗 连接到腾讯云数据库...")
else:
# 本地数据库配置
conn = pymysql.connect(
host='localhost',
user='root',
password='123456',
database='pro_db', # 修正数据库名
charset='utf8mb4'
)
print("🔗 连接到本地数据库...")
cursor = conn.cursor()
# 创建 prompt_template 表
# 创建 prompt_template 表
cursor.execute("""
CREATE TABLE IF NOT EXISTS prompt_template (
id INT PRIMARY KEY AUTO_INCREMENT,
@@ -3652,12 +3676,14 @@ def init_db():
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
""")
print("✅ prompt_template 表创建/检查完成")
# 检查是否已有模板数据
cursor.execute("SELECT COUNT(*) FROM prompt_template")
count = cursor.fetchone()[0]
if count == 0:
print("📝 开始插入模板数据...")
# 插入模板数据
sql = """
INSERT INTO prompt_template
@@ -3665,28 +3691,35 @@ def init_db():
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
"""
success_count = 0
for template in templates: # templates 变量来自同文件中的模板列表
cursor.execute(sql, (
template['name'],
template['description'],
template.get('category', ''),
template.get('industry', ''),
template.get('profession', ''),
template.get('sub_category', ''),
template['system_prompt'],
template.get('is_default', False)
))
try:
cursor.execute(sql, (
template['name'],
template['description'],
template.get('category', ''),
template.get('industry', ''),
template.get('profession', ''),
template.get('sub_category', ''),
template['system_prompt'],
template.get('is_default', False)
))
success_count += 1
except Exception as e:
print(f"⚠️ 插入模板 '{template['name']}' 失败: {str(e)}")
print("模板数据初始化完成")
print(f"✅ 成功插入 {success_count}模板数据!")
else:
print("模板数据已存在,跳过初始化。")
print(f" 模板数据已存在 ({count} 条记录),跳过初始化。")
# 提交事务
conn.commit()
print("数据库初始化完成!")
print("🎉 数据库初始化完成!")
except Exception as e:
print(f"初始化数据库失败: {str(e)}")
print(f"初始化数据库失败: {str(e)}")
import traceback
traceback.print_exc()
if 'conn' in locals():
conn.rollback()
finally:
@@ -3695,5 +3728,36 @@ def init_db():
if 'conn' in locals():
conn.close()
def init_tencent_db():
"""专门用于初始化腾讯云数据库的便捷函数"""
print("🚀 开始初始化腾讯云数据库...")
init_db('tencent')
def init_local_db():
"""专门用于初始化本地数据库的便捷函数"""
print("🚀 开始初始化本地数据库...")
init_db('local')
if __name__ == '__main__':
init_db()
import sys
# 支持命令行参数选择数据库类型
if len(sys.argv) > 1:
db_type = sys.argv[1].lower()
if db_type in ['tencent', 't']:
init_tencent_db()
elif db_type in ['local', 'l']:
init_local_db()
else:
print("❌ 无效的数据库类型参数")
print("用法: python promptsTemplates.py [local|tencent]")
print(" local 或 l - 初始化本地数据库")
print(" tencent 或 t - 初始化腾讯云数据库")
sys.exit(1)
else:
# 默认初始化本地数据库
print(" 未指定数据库类型,默认初始化本地数据库")
print("💡 提示:可以使用 'python promptsTemplates.py tencent' 初始化腾讯云数据库")
init_local_db()

View File

@@ -132,6 +132,9 @@ def index():
template_id = request.form.get('template_id')
generated_text = generate_with_llm(form.input_text.data, template_id)
# 获取搜索状态
search_state = request.form.get('search_state', '')
# 获取默认用户的 uid
try:
conn = pymysql.connect(
@@ -164,7 +167,8 @@ def index():
return render_template('generate.html', form=form, prompt=prompt, templates=templates,
get_template_icon=get_template_icon, industries=industries,
professions=professions, categories=categories,
sub_categories=sub_categories, selected_template_id=template_id)
sub_categories=sub_categories, selected_template_id=template_id,
search_state=search_state)
return render_template('generate.html', form=form, prompt=None, templates=templates,
get_template_icon=get_template_icon, industries=industries,
professions=professions, categories=categories,

View File

@@ -20,8 +20,11 @@
<i class="fas fa-brain"></i> 专家模式
</a>
</div>
<form method="POST" class="generate-form">
<form method="POST" class="generate-form" id="generateForm">
{{ form.hidden_tag() }}
<!-- 隐藏字段保存搜索状态 -->
<input type="hidden" id="searchState" name="search_state" value="{{ search_state or '' }}">
<input type="hidden" id="filterState" name="filter_state" value="">
<div class="search-section">
<div class="search-box">
@@ -131,7 +134,7 @@
</form>
{% if prompt %}
<div class="result-section">
<div class="result-section animate-fade-in">
<div class="result-card">
<div class="result-header">
<h2>生成结果</h2>
@@ -819,6 +822,353 @@
border-radius: 4px;
cursor: pointer;
}
/* ==================== 动画效果 ==================== */
/* 淡入动画 */
.animate-fade-in {
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 滑入动画 */
.animate-slide-in {
animation: slideIn 0.5s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* 缩放动画 */
.animate-scale-in {
animation: scaleIn 0.4s ease-out;
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* 结果卡片动画 */
.result-section {
animation: slideInUp 0.6s ease-out;
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(40px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 结果卡片内容动画 */
.result-card {
animation: fadeInScale 0.8s ease-out 0.2s both;
}
@keyframes fadeInScale {
from {
opacity: 0;
transform: scale(0.95) translateY(20px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
/* 按钮悬停动画 */
.btn {
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.btn:active {
transform: translateY(0);
}
/* 按钮点击波纹效果 */
.btn::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.btn:active::before {
width: 300px;
height: 300px;
}
/* 生成按钮特殊动画 */
.btn-generate {
position: relative;
overflow: hidden;
}
.btn-generate.generating {
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(74, 144, 226, 0.7);
}
70% {
box-shadow: 0 0 0 10px rgba(74, 144, 226, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(74, 144, 226, 0);
}
}
/* 模板卡片悬停动画 */
.template-card {
transition: all 0.3s ease;
}
.template-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
/* 搜索框焦点动画 */
.search-input:focus {
animation: focusGlow 0.3s ease-out;
}
@keyframes focusGlow {
from {
box-shadow: 0 0 0 0 rgba(74, 144, 226, 0.4);
}
to {
box-shadow: 0 0 0 4px rgba(74, 144, 226, 0.1);
}
}
/* 加载动画 */
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* 成功提示动画 */
.success-message {
animation: slideInDown 0.5s ease-out;
}
@keyframes slideInDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 错误提示动画 */
.error-message {
animation: shake 0.5s ease-in-out;
}
@keyframes shake {
0%, 100% {
transform: translateX(0);
}
25% {
transform: translateX(-5px);
}
75% {
transform: translateX(5px);
}
}
/* 复制成功动画 */
.copy-success {
animation: bounce 0.6s ease-out;
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(-10px);
}
60% {
transform: translateY(-5px);
}
}
/* 响应式动画优化 */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* 高亮文本动画 */
.highlight {
background: linear-gradient(120deg, #a8edea 0%, #fed6e3 100%);
padding: 2px 4px;
border-radius: 3px;
animation: highlightPulse 0.5s ease-out;
}
@keyframes highlightPulse {
from {
background: #ffeb3b;
}
to {
background: linear-gradient(120deg, #a8edea 0%, #fed6e3 100%);
}
}
/* 搜索框聚焦状态 */
.search-focused {
transform: scale(1.02);
box-shadow: 0 4px 20px rgba(74, 144, 226, 0.2);
}
/* 筛选器变化动画 */
.filter-changed {
animation: filterChange 0.3s ease-out;
}
@keyframes filterChange {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
/* 加载状态样式 */
.generating {
position: relative;
overflow: hidden;
}
.generating::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% {
left: -100%;
}
100% {
left: 100%;
}
}
/* 结果内容动画 */
.result-content {
transition: all 0.6s ease-out;
}
/* 模板卡片加载动画 */
.template-card {
transition: all 0.5s ease-out;
}
/* 按钮组动画 */
.btn-group {
display: flex;
gap: 0.5rem;
animation: slideInUp 0.6s ease-out 0.3s both;
}
/* 表单动画 */
.generate-form {
animation: fadeIn 0.8s ease-out;
}
/* 搜索区域动画 */
.search-section {
animation: slideInDown 0.6s ease-out 0.1s both;
}
/* 模板区域动画 */
.templates-section {
animation: fadeIn 0.8s ease-out 0.2s both;
}
/* 输入区域动画 */
.input-section {
animation: slideInUp 0.6s ease-out 0.4s both;
}
/* 操作区域动画 */
.action-section {
animation: slideInUp 0.6s ease-out 0.5s both;
}
</style>
<script>
@@ -1274,6 +1624,341 @@ document.addEventListener('DOMContentLoaded', function() {
firstTemplate.checked = true;
}
}
// 恢复搜索状态
restoreSearchState();
});
// 保存搜索状态
function saveSearchState() {
const searchTerm = document.getElementById('templateSearch').value;
const industryFilter = document.getElementById('industryFilter').value;
const professionFilter = document.getElementById('professionFilter').value;
const subCategoryFilter = document.getElementById('subCategoryFilter').value;
const activeTab = document.querySelector('.tab.active')?.dataset.category || 'all';
const searchState = {
searchTerm: searchTerm,
industry: industryFilter,
profession: professionFilter,
subCategory: subCategoryFilter,
activeTab: activeTab
};
console.log('保存搜索状态:', searchState);
document.getElementById('searchState').value = JSON.stringify(searchState);
console.log('搜索状态已保存到隐藏字段:', document.getElementById('searchState').value);
}
// 恢复搜索状态
function restoreSearchState() {
const searchStateValue = document.getElementById('searchState').value;
console.log('搜索状态值:', searchStateValue);
if (searchStateValue) {
try {
const searchState = JSON.parse(searchStateValue);
console.log('解析的搜索状态:', searchState);
// 恢复搜索框
if (searchState.searchTerm) {
document.getElementById('templateSearch').value = searchState.searchTerm;
console.log('恢复搜索词:', searchState.searchTerm);
}
// 恢复筛选器
if (searchState.industry) {
document.getElementById('industryFilter').value = searchState.industry;
console.log('恢复行业筛选:', searchState.industry);
}
if (searchState.profession) {
document.getElementById('professionFilter').value = searchState.profession;
console.log('恢复职业筛选:', searchState.profession);
}
if (searchState.subCategory) {
document.getElementById('subCategoryFilter').value = searchState.subCategory;
console.log('恢复子分类筛选:', searchState.subCategory);
}
// 恢复活动标签
if (searchState.activeTab) {
document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));
const activeTab = document.querySelector(`[data-category="${searchState.activeTab}"]`);
if (activeTab) {
activeTab.classList.add('active');
console.log('恢复活动标签:', searchState.activeTab);
}
}
// 手动执行搜索和筛选逻辑
setTimeout(() => {
console.log('开始执行搜索和筛选...');
performSearchAndFilter();
}, 100);
} catch (e) {
console.error('恢复搜索状态失败:', e);
}
} else {
console.log('没有搜索状态需要恢复');
}
}
// 执行搜索和筛选的综合函数
function performSearchAndFilter() {
const searchTerm = document.getElementById('templateSearch').value.toLowerCase().trim();
const industry = document.getElementById('industryFilter').value;
const profession = document.getElementById('professionFilter').value;
const subCategory = document.getElementById('subCategoryFilter').value;
const category = document.querySelector('.tab.active')?.dataset.category || 'all';
const cards = document.querySelectorAll('.template-card');
let visibleCount = 0;
cards.forEach(card => {
const name = card.querySelector('h3').textContent.toLowerCase();
const description = card.querySelector('p').textContent.toLowerCase();
const cardIndustry = card.dataset.industry.toLowerCase();
const cardProfession = card.dataset.profession.toLowerCase();
const cardCategory = card.dataset.category.toLowerCase();
const cardSubCategory = card.dataset.subcategory.toLowerCase();
// 检查搜索匹配
const matchSearch = !searchTerm ||
name.includes(searchTerm) ||
description.includes(searchTerm) ||
cardIndustry.includes(searchTerm) ||
cardProfession.includes(searchTerm) ||
cardCategory.includes(searchTerm) ||
cardSubCategory.includes(searchTerm);
// 检查筛选匹配
const matchIndustry = industry === 'all' || cardIndustry === industry.toLowerCase();
const matchProfession = profession === 'all' || cardProfession === profession.toLowerCase();
const matchSubCategory = subCategory === 'all' || cardSubCategory === subCategory.toLowerCase();
const matchCategory = category === 'all' || cardCategory === category.toLowerCase();
const matchFilters = matchIndustry && matchProfession && matchSubCategory && matchCategory;
if (matchSearch && matchFilters) {
card.style.display = 'block';
visibleCount++;
// 高亮匹配文本
if (searchTerm) {
card.querySelector('h3').innerHTML = highlightText(card.querySelector('h3').textContent, searchTerm);
card.querySelector('p').innerHTML = highlightText(card.querySelector('p').textContent, searchTerm);
}
} else {
card.style.display = 'none';
}
});
// 更新统计信息
const searchStats = document.querySelector('.search-count');
if (searchStats) {
searchStats.textContent = `显示 ${visibleCount}/${cards.length} 个模板`;
}
// 显示无结果提示
const noResultsEl = document.querySelector('.no-results');
if (visibleCount === 0) {
if (!noResultsEl) {
const noResults = document.createElement('div');
noResults.className = 'no-results';
noResults.innerHTML = `
<div class="no-results-content">
<i class="fas fa-search"></i>
<h3>未找到匹配的模板</h3>
<p>请尝试其他搜索关键词</p>
<button class="btn-reset-search">清除搜索</button>
</div>
`;
document.querySelector('.template-grid').appendChild(noResults);
// 绑定清除搜索按钮事件
noResults.querySelector('.btn-reset-search').addEventListener('click', () => {
document.getElementById('templateSearch').value = '';
document.getElementById('industryFilter').value = 'all';
document.getElementById('professionFilter').value = 'all';
document.getElementById('subCategoryFilter').value = 'all';
document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));
document.querySelector('[data-category="all"]').classList.add('active');
performSearchAndFilter();
});
}
} else if (noResultsEl) {
noResultsEl.remove();
}
}
// 高亮文本函数
function highlightText(text, searchTerm) {
if (!searchTerm) return text;
const regex = new RegExp(`(${searchTerm})`, 'gi');
return text.replace(regex, '<span class="highlight">$1</span>');
}
// 表单提交前保存搜索状态
document.getElementById('generateForm').addEventListener('submit', function() {
saveSearchState();
// 添加生成按钮动画效果
const generateBtn = document.querySelector('.btn-generate');
generateBtn.classList.add('generating');
generateBtn.innerHTML = '<span class="loading-spinner"></span> 生成中...';
generateBtn.disabled = true;
});
// 增强的复制功能
function copyText(text) {
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(text).then(() => {
showCopySuccess();
}).catch(() => {
fallbackCopyText(text);
});
} else {
fallbackCopyText(text);
}
}
// 备用复制方法
function fallbackCopyText(text) {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand('copy');
showCopySuccess();
} catch (err) {
console.error('复制失败:', err);
showCopyError();
}
document.body.removeChild(textArea);
}
// 显示复制成功动画
function showCopySuccess() {
const copyBtn = document.querySelector('.btn-copy');
const originalText = copyBtn.innerHTML;
copyBtn.classList.add('copy-success');
copyBtn.innerHTML = '<i class="fas fa-check"></i> 已复制';
copyBtn.style.background = '#4CAF50';
setTimeout(() => {
copyBtn.classList.remove('copy-success');
copyBtn.innerHTML = originalText;
copyBtn.style.background = '';
}, 2000);
}
// 显示复制错误
function showCopyError() {
const copyBtn = document.querySelector('.btn-copy');
const originalText = copyBtn.innerHTML;
copyBtn.innerHTML = '<i class="fas fa-times"></i> 复制失败';
copyBtn.style.background = '#f44336';
setTimeout(() => {
copyBtn.innerHTML = originalText;
copyBtn.style.background = '';
}, 2000);
}
// 添加页面加载动画
function addPageLoadAnimations() {
// 为模板卡片添加延迟动画
const templateCards = document.querySelectorAll('.template-card');
templateCards.forEach((card, index) => {
card.style.opacity = '0';
card.style.transform = 'translateY(20px)';
setTimeout(() => {
card.style.transition = 'all 0.5s ease-out';
card.style.opacity = '1';
card.style.transform = 'translateY(0)';
}, index * 50); // 每个卡片延迟50ms
});
}
// 添加搜索框动画
function addSearchAnimations() {
const searchInput = document.getElementById('templateSearch');
searchInput.addEventListener('focus', function() {
this.parentElement.classList.add('search-focused');
});
searchInput.addEventListener('blur', function() {
this.parentElement.classList.remove('search-focused');
});
}
// 添加筛选器动画
function addFilterAnimations() {
const filters = document.querySelectorAll('.custom-select');
filters.forEach(filter => {
filter.addEventListener('change', function() {
this.classList.add('filter-changed');
setTimeout(() => {
this.classList.remove('filter-changed');
}, 300);
});
});
}
// 添加结果区域动画
function addResultAnimations() {
const resultSection = document.querySelector('.result-section');
if (resultSection) {
// 滚动到结果区域
resultSection.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
// 添加结果内容动画
const resultContent = resultSection.querySelector('.result-content');
if (resultContent) {
resultContent.style.opacity = '0';
resultContent.style.transform = 'translateY(20px)';
setTimeout(() => {
resultContent.style.transition = 'all 0.6s ease-out';
resultContent.style.opacity = '1';
resultContent.style.transform = 'translateY(0)';
}, 200);
}
}
}
// 初始化所有动画
function initializeAnimations() {
addPageLoadAnimations();
addSearchAnimations();
addFilterAnimations();
// 如果有结果区域,添加结果动画
if (document.querySelector('.result-section')) {
addResultAnimations();
}
}
// 页面加载完成后初始化动画
document.addEventListener('DOMContentLoaded', function() {
// 延迟初始化动画,确保页面完全加载
setTimeout(initializeAnimations, 100);
});
// 收藏功能