mirror of
https://github.com/sligter/LandPPT.git
synced 2026-08-28 23:31:06 +08:00
Add new presentation templates and configuration file
- Created a default business template (商务.json) with a modern design. - Added a neumorphic style template (拟态风.json) emphasizing depth and shadow effects. - Introduced a liquid glass template (液体玻璃.json) featuring animated backgrounds. - Implemented a terminal-themed template (终端风.json) with glitch effects and terminal aesthetics. - Updated the configuration file (uv.toml) for package management with additional index URLs and cache settings.
This commit is contained in:
@@ -17,3 +17,7 @@ prompts.md
|
||||
temp/
|
||||
*.tmp
|
||||
*.cache
|
||||
|
||||
# uv cache and lock files
|
||||
.uv-cache/
|
||||
# Keep uv.lock for reproducible builds
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
# 图表验证警告修复总结
|
||||
|
||||
## 问题描述
|
||||
在PDF转换过程中出现警告:
|
||||
```
|
||||
WARNING:landppt.services.pyppeteer_pdf_converter:⚠️ 警告:部分图表内容可能未完全渲染
|
||||
```
|
||||
|
||||
## 问题分析
|
||||
|
||||
### 原因1: Canvas内容检测过于严格
|
||||
- **原问题**: 只检查非白色像素,导致很多有效图表被误判为未渲染
|
||||
- **影响**: 白色背景或浅色图表无法通过验证
|
||||
|
||||
### 原因2: ECharts检测逻辑不完善
|
||||
- **原问题**: 检测逻辑过于复杂,容易出现遗漏
|
||||
- **影响**: 有效的ECharts实例被误判为未渲染
|
||||
|
||||
### 原因3: 验证阈值过高
|
||||
- **原问题**: 要求80%的图表元素都有内容才通过验证
|
||||
- **影响**: 即使大部分图表正常也会触发警告
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 1. 优化Canvas内容检测
|
||||
|
||||
#### 修复前
|
||||
```javascript
|
||||
// 只检查非白色像素
|
||||
if (a > 0 && (r !== 255 || g !== 255 || b !== 255)) {
|
||||
hasContent = true;
|
||||
}
|
||||
```
|
||||
|
||||
#### 修复后
|
||||
```javascript
|
||||
// 方法1: 降低dataURL长度阈值
|
||||
if (dataURL && dataURL.length > 500) { // 从1000降到500
|
||||
hasContent = true;
|
||||
}
|
||||
|
||||
// 方法2: 检查任何非透明像素
|
||||
for (let i = 3; i < imageData.data.length; i += 4) {
|
||||
if (imageData.data[i] > 0) { // 只要有透明度变化
|
||||
hasContent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 方法3: 检查颜色变化(不限于非白色)
|
||||
if (r !== imageData.data[0] || g !== imageData.data[1] || b !== imageData.data[2]) {
|
||||
hasContent = true;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 增强ECharts检测逻辑
|
||||
|
||||
#### 修复前
|
||||
```javascript
|
||||
// 简单的像素检查
|
||||
for (let i = 3; i < imageData.data.length; i += 4) {
|
||||
if (imageData.data[i] > 0) {
|
||||
results.renderedEchartsInstances++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 修复后
|
||||
```javascript
|
||||
// 多重检测策略
|
||||
let contentRendered = false;
|
||||
|
||||
if (canvas) {
|
||||
// 检查canvas数据URL
|
||||
const dataURL = canvas.toDataURL();
|
||||
if (dataURL && dataURL.length > 500) {
|
||||
contentRendered = true;
|
||||
} else {
|
||||
// 检查像素数据
|
||||
// ... 像素检查逻辑
|
||||
}
|
||||
} else if (svg) {
|
||||
// 检查SVG图形元素
|
||||
const graphicElements = svg.querySelectorAll('path, circle, rect, line, polygon, text, g');
|
||||
if (graphicElements.length > 0) {
|
||||
contentRendered = true;
|
||||
}
|
||||
} else {
|
||||
// 如果有配置但找不到渲染元素,假设已渲染
|
||||
contentRendered = true;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 智能验证逻辑
|
||||
|
||||
#### 修复前
|
||||
```javascript
|
||||
// 严格的80%阈值
|
||||
results.contentVerified = totalExpected === 0 || totalRendered >= totalExpected * 0.8;
|
||||
```
|
||||
|
||||
#### 修复后
|
||||
```javascript
|
||||
// 多层次智能验证
|
||||
let contentVerified = false;
|
||||
|
||||
if (totalExpected === 0) {
|
||||
// 没有图表元素,验证通过
|
||||
contentVerified = true;
|
||||
} else if (totalRendered >= totalExpected * 0.6) {
|
||||
// 降低阈值到60%
|
||||
contentVerified = true;
|
||||
} else if (results.chartInstances > 0 || results.echartsInstances > 0 || results.svgElements > 0) {
|
||||
// 有图表库实例或SVG元素,认为可能已渲染
|
||||
contentVerified = true;
|
||||
} else if (totalRendered > 0) {
|
||||
// 只要有任何渲染内容就认为部分成功
|
||||
contentVerified = true;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 改进日志输出
|
||||
|
||||
#### 修复前
|
||||
```
|
||||
⚠️ 警告:部分图表内容可能未完全渲染
|
||||
```
|
||||
|
||||
#### 修复后
|
||||
```
|
||||
📈 渲染完成度: 85.7% (6/7)
|
||||
⚠️ 图表渲染检测: 85.7%完成 (6/7),但PDF生成将继续
|
||||
✅ 图表内容验证通过: 100.0%渲染完成
|
||||
```
|
||||
|
||||
### 5. 错误恢复机制
|
||||
|
||||
#### 新增功能
|
||||
```python
|
||||
except Exception as error:
|
||||
logger.error(f"❌ 最终图表验证失败: {error}")
|
||||
# 返回保守的验证结果,假设内容已渲染
|
||||
return {
|
||||
'contentVerified': True, # 验证失败时保守处理
|
||||
'errors': [f"验证失败: {error}"]
|
||||
}
|
||||
```
|
||||
|
||||
## 修复效果
|
||||
|
||||
### 测试结果对比
|
||||
|
||||
#### 修复前
|
||||
```
|
||||
WARNING:landppt.services.pyppeteer_pdf_converter:⚠️ 警告:部分图表内容可能未完全渲染
|
||||
✅ PDF转换成功!
|
||||
```
|
||||
|
||||
#### 修复后
|
||||
```
|
||||
📈 渲染完成度: 100.0% (3/3)
|
||||
✅ 图表内容验证通过: 100.0%渲染完成
|
||||
✅ PDF转换成功!
|
||||
```
|
||||
|
||||
### 改进指标
|
||||
|
||||
1. **检测准确性**: 提升约40%
|
||||
- Canvas检测: 从严格的非白色检测改为多重检测策略
|
||||
- ECharts检测: 增加SVG和配置检测
|
||||
- 验证阈值: 从80%降低到60%
|
||||
|
||||
2. **容错能力**: 显著增强
|
||||
- 多层次验证逻辑
|
||||
- 保守的错误处理
|
||||
- 智能的内容判断
|
||||
|
||||
3. **用户体验**: 大幅改善
|
||||
- 消除误报警告
|
||||
- 提供详细的渲染统计
|
||||
- 更友好的日志信息
|
||||
|
||||
## 兼容性
|
||||
|
||||
- ✅ **Chart.js**: 完全支持,包括各种颜色和背景
|
||||
- ✅ **ECharts**: 完全支持,包括Canvas和SVG渲染模式
|
||||
- ✅ **D3.js**: 完全支持,SVG图形检测
|
||||
- ✅ **其他图表库**: 通用的Canvas/SVG检测机制
|
||||
|
||||
## 总结
|
||||
|
||||
通过这次修复:
|
||||
|
||||
1. **消除了误报警告**: 正常的图表不再触发"未完全渲染"警告
|
||||
2. **提升了检测精度**: 更准确地识别图表内容是否已渲染
|
||||
3. **增强了容错能力**: 即使检测失败也能优雅处理
|
||||
4. **改善了用户体验**: 提供更详细和友好的反馈信息
|
||||
|
||||
修复后的系统能够更可靠地检测各种类型的图表内容,确保PDF转换过程的稳定性和用户体验。
|
||||
@@ -1,178 +0,0 @@
|
||||
# PyppeteerPDFConverter 优化总结
|
||||
|
||||
## 优化目标
|
||||
确保页面所有内容都能完全加载完毕后再生成PDF,特别是图表、动态内容、字体和外部资源。
|
||||
|
||||
## 主要优化内容
|
||||
|
||||
### 1. 增强的等待策略
|
||||
|
||||
#### 1.1 基础资源等待
|
||||
- **网络等待策略**: 从 `domcontentloaded` 改为 `networkidle0`,确保所有网络请求完成
|
||||
- **超时时间**: 增加到 15-20 秒,给复杂页面更多加载时间
|
||||
- **图片加载**: 添加专门的图片加载完成检测
|
||||
|
||||
#### 1.2 字体和外部资源等待 (`_wait_for_fonts_and_resources`)
|
||||
```python
|
||||
# 等待字体加载完成
|
||||
document.fonts.ready.then(resolve)
|
||||
|
||||
# 等待样式表加载完成
|
||||
Array.from(document.styleSheets).forEach(sheet => {
|
||||
const rules = sheet.cssRules || sheet.rules;
|
||||
})
|
||||
|
||||
# 触发懒加载内容
|
||||
const lazyElements = document.querySelectorAll('[data-src], [loading="lazy"], .lazy');
|
||||
```
|
||||
|
||||
#### 1.3 智能等待时间调整
|
||||
根据页面复杂度动态调整等待时间:
|
||||
- 图表数量 × 3 分
|
||||
- SVG 数量 × 2 分
|
||||
- 图片数量 × 1 分
|
||||
- 脚本数量 × 1 分
|
||||
- 元素总数 ÷ 100
|
||||
|
||||
### 2. 图表渲染优化
|
||||
|
||||
#### 2.1 扩展的图表检测 (`_wait_for_charts_and_dynamic_content`)
|
||||
- **Chart.js**: 检测实例数量和canvas内容渲染
|
||||
- **ECharts**: 检测实例和配置数据
|
||||
- **D3.js**: 检测SVG元素和图形内容
|
||||
- **尝试次数**: 从20次增加到30次
|
||||
- **最大等待时间**: 从10秒增加到15秒
|
||||
|
||||
#### 2.2 图表内容验证
|
||||
```javascript
|
||||
// Canvas内容检测
|
||||
const imageData = ctx.getImageData(0, 0, sampleSize, sampleSize);
|
||||
for (let i = 3; i < imageData.data.length; i += 4) {
|
||||
if (imageData.data[i] > 0) { // 检测非透明像素
|
||||
hasContent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SVG内容检测
|
||||
const graphicElements = svg.querySelectorAll('path, circle, rect, line, polygon');
|
||||
if (graphicElements.length > 0) {
|
||||
// 检查元素的bounding box和样式
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 强制图表初始化 (`_force_chart_initialization`)
|
||||
- 重新执行图表相关脚本
|
||||
- 禁用所有动画以加快渲染
|
||||
- 强制调用图表的render/update方法
|
||||
- 触发resize事件确保图表适应容器
|
||||
|
||||
### 3. 综合页面就绪检查 (`_comprehensive_page_ready_check`)
|
||||
|
||||
检查项目包括:
|
||||
- ✅ DOM完全加载 (`document.readyState === 'complete'`)
|
||||
- ✅ 字体加载完成 (`document.fonts.status === 'loaded'`)
|
||||
- ✅ 所有图片加载完成 (`img.complete && img.naturalWidth > 0`)
|
||||
- ✅ 所有脚本加载完成 (`script.readyState === 'complete'`)
|
||||
- ✅ 所有样式表可访问 (`sheet.cssRules`)
|
||||
- ✅ 图表内容渲染完成 (至少80%的图表有实际内容)
|
||||
- ✅ 无活跃动画
|
||||
- ✅ 页面有可见内容
|
||||
|
||||
### 4. 渲染稳定性增强
|
||||
|
||||
#### 4.1 多层等待保障
|
||||
```python
|
||||
# 1. 基础DOM等待
|
||||
await page.waitForSelector('body', {'timeout': 5000})
|
||||
|
||||
# 2. 资源加载等待
|
||||
await self._wait_for_fonts_and_resources(page)
|
||||
|
||||
# 3. 图表渲染等待
|
||||
await self._wait_for_charts_and_dynamic_content(page)
|
||||
|
||||
# 4. 最终验证等待
|
||||
await self._comprehensive_page_ready_check(page)
|
||||
|
||||
# 5. 稳定性等待
|
||||
await asyncio.sleep(0.5)
|
||||
```
|
||||
|
||||
#### 4.2 强制重排和重绘
|
||||
```javascript
|
||||
// 强制重排
|
||||
document.body.offsetHeight;
|
||||
|
||||
// 触发resize事件
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
|
||||
// 等待渲染帧
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(resolve);
|
||||
});
|
||||
```
|
||||
|
||||
### 5. 批处理优化
|
||||
|
||||
- **共享浏览器实例**: 避免重复启动浏览器
|
||||
- **批次大小调整**: 根据文件数量动态调整批次大小
|
||||
- **重试机制**: 失败时最多重试5次
|
||||
- **内存管理**: 批次间添加清理等待
|
||||
|
||||
### 6. 错误处理和日志
|
||||
|
||||
#### 6.1 详细的进度日志
|
||||
```
|
||||
🎯 等待图表和动态内容完全渲染...
|
||||
📊 图表检查 (第1次): DOM:true, Chart.js:1/1, ECharts:1/1, D3:1/1, 动画:false
|
||||
📊 页面复杂度分析: 图表:3, 图片:0, 总分:12, 等待时间:1.5s
|
||||
📊 页面状态: DOM:true, 字体:true, 图片:true, 脚本:true, 样式:true, 图表:true, 无动画:true, 可见内容:true
|
||||
✅ 页面完全就绪
|
||||
```
|
||||
|
||||
#### 6.2 错误恢复
|
||||
- 图表检测失败时的保守处理
|
||||
- 资源加载超时的优雅降级
|
||||
- 批处理中单个文件失败不影响整体进度
|
||||
|
||||
## 性能影响
|
||||
|
||||
### 优化前
|
||||
- 等待策略: `domcontentloaded` + 固定等待
|
||||
- 图表检测: 基础检测,容易遗漏
|
||||
- 转换速度: 快但可能内容不完整
|
||||
|
||||
### 优化后
|
||||
- 等待策略: `networkidle0` + 智能动态等待
|
||||
- 图表检测: 多层验证,确保内容完整
|
||||
- 转换速度: 稍慢但内容完整性大幅提升
|
||||
|
||||
### 测试结果
|
||||
- ✅ 转换成功率: 100%
|
||||
- ⏱️ 平均耗时: 15-20秒 (复杂页面)
|
||||
- 📊 内容完整性: 显著提升
|
||||
- 🎯 图表渲染: 完全支持Chart.js、ECharts、D3.js
|
||||
|
||||
## 使用建议
|
||||
|
||||
1. **简单页面**: 优化后的等待策略不会显著增加时间
|
||||
2. **复杂图表页面**: 建议使用单文件转换以获得最佳效果
|
||||
3. **批量处理**: 系统会自动调整批次大小和等待时间
|
||||
4. **调试**: 查看详细日志了解页面加载状态
|
||||
|
||||
## 配置选项
|
||||
|
||||
```python
|
||||
# 自定义等待时间
|
||||
options = {
|
||||
'viewportWidth': 1280,
|
||||
'viewportHeight': 720,
|
||||
'maxWaitTime': 20000, # 最大等待时间
|
||||
'complexityThreshold': 15 # 复杂度阈值
|
||||
}
|
||||
|
||||
await converter.html_to_pdf(html_file, pdf_file, options)
|
||||
```
|
||||
|
||||
这些优化确保了页面所有内容都能完全加载完毕后再生成PDF,特别是对于包含动态图表和异步内容的复杂页面。
|
||||
BIN
Binary file not shown.
+2
-9
@@ -40,15 +40,10 @@ dependencies = [
|
||||
"langchain-google-genai>=1.0.0",
|
||||
"langgraph>=0.1.0",
|
||||
"click>=8.0.0",
|
||||
"pydantic>=2.0.0",
|
||||
"python-dotenv>=1.0.0",
|
||||
"chardet>=5.0.0",
|
||||
"pypdf>=4.0.0",
|
||||
"python-docx>=1.1.0",
|
||||
"pandas>=2.0.0",
|
||||
"requests>=2.31.0",
|
||||
"beautifulsoup4>=4.12.0",
|
||||
"markdown>=3.5.0",
|
||||
"rich>=13.0.0",
|
||||
"pydantic-settings>=2.0.0",
|
||||
"tavily-python>=0.7.8",
|
||||
@@ -56,6 +51,7 @@ dependencies = [
|
||||
"markitdown[all]>=0.1.2",
|
||||
"onnxruntime==1.19.2",
|
||||
"pyppeteer>=1.0.2",
|
||||
"apryse-sdk>=11.5.0",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
@@ -64,10 +60,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/landppt"]
|
||||
sources = ["src"]
|
||||
|
||||
[tool.hatch.pypi]
|
||||
extra-index-urls = ["https://pypi.apryse.com"]
|
||||
sources = ["src"]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -280,6 +280,18 @@ async def main(clean_start=True):
|
||||
print("\n❌ Database connection test failed")
|
||||
return False
|
||||
|
||||
# Import default templates from examples (force import for setup)
|
||||
print("\n📋 Importing default templates from examples...")
|
||||
try:
|
||||
from landppt.database.create_default_template import ensure_default_templates_exist_first_time
|
||||
template_ids = await ensure_default_templates_exist_first_time()
|
||||
if template_ids:
|
||||
print(f"✅ Successfully imported {len(template_ids)} templates")
|
||||
else:
|
||||
print("⚠️ No templates were imported")
|
||||
except Exception as e:
|
||||
print(f"❌ Failed to import templates: {e}")
|
||||
|
||||
# Final verification - ensure database is clean
|
||||
print("\n🔍 Final verification - ensuring clean database...")
|
||||
if not await verify_clean_database():
|
||||
|
||||
@@ -3,7 +3,11 @@ Create default global master template
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Any
|
||||
from .database import AsyncSessionLocal
|
||||
from .service import DatabaseService
|
||||
|
||||
@@ -169,18 +173,112 @@ DEFAULT_TEMPLATE_HTML = """<!DOCTYPE html>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
async def create_default_global_template():
|
||||
"""Create default global master template"""
|
||||
def get_template_examples_path() -> Path:
|
||||
"""Get the path to template_examples directory"""
|
||||
# 从当前文件位置向上查找项目根目录
|
||||
current_file = Path(__file__)
|
||||
# 从 src/landppt/database/create_default_template.py 向上四级到项目根目录
|
||||
project_root = current_file.parent.parent.parent.parent
|
||||
template_examples_path = project_root / "template_examples"
|
||||
|
||||
logger.info(f"Looking for template_examples at: {template_examples_path}")
|
||||
|
||||
if not template_examples_path.exists():
|
||||
logger.warning(f"Template examples directory not found at: {template_examples_path}")
|
||||
return None
|
||||
|
||||
return template_examples_path
|
||||
|
||||
|
||||
def load_template_from_json(json_file_path: Path) -> Dict[str, Any]:
|
||||
"""Load template data from JSON file"""
|
||||
try:
|
||||
with open(json_file_path, 'r', encoding='utf-8') as f:
|
||||
template_data = json.load(f)
|
||||
|
||||
# 移除导出信息,因为这是新导入的模板
|
||||
if 'export_info' in template_data:
|
||||
del template_data['export_info']
|
||||
|
||||
# 确保必要字段存在
|
||||
if 'template_name' not in template_data or 'html_template' not in template_data:
|
||||
logger.error(f"Invalid template JSON file: {json_file_path}")
|
||||
return None
|
||||
|
||||
# 设置默认值
|
||||
template_data.setdefault('description', '')
|
||||
template_data.setdefault('tags', [])
|
||||
template_data.setdefault('is_default', False)
|
||||
template_data.setdefault('is_active', True)
|
||||
template_data.setdefault('created_by', 'system')
|
||||
|
||||
return template_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading template from {json_file_path}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
async def import_templates_from_examples() -> List[int]:
|
||||
"""Import all templates from template_examples directory"""
|
||||
template_examples_path = get_template_examples_path()
|
||||
if not template_examples_path:
|
||||
logger.warning("Template examples directory not found, skipping import")
|
||||
return []
|
||||
|
||||
imported_template_ids = []
|
||||
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
db_service = DatabaseService(session)
|
||||
|
||||
|
||||
# 获取所有JSON文件
|
||||
json_files = list(template_examples_path.glob("*.json"))
|
||||
logger.info(f"Found {len(json_files)} template files in {template_examples_path}")
|
||||
|
||||
for json_file in json_files:
|
||||
logger.info(f"Processing template file: {json_file.name}")
|
||||
|
||||
# 加载模板数据
|
||||
template_data = load_template_from_json(json_file)
|
||||
if not template_data:
|
||||
continue
|
||||
|
||||
# 检查模板是否已存在
|
||||
existing = await db_service.get_global_master_template_by_name(template_data['template_name'])
|
||||
if existing:
|
||||
logger.info(f"Template '{template_data['template_name']}' already exists, skipping")
|
||||
continue
|
||||
|
||||
# 创建模板
|
||||
try:
|
||||
template = await db_service.create_global_master_template(template_data)
|
||||
imported_template_ids.append(template.id)
|
||||
logger.info(f"Successfully imported template '{template_data['template_name']}' with ID: {template.id}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create template '{template_data['template_name']}': {e}")
|
||||
continue
|
||||
|
||||
logger.info(f"Successfully imported {len(imported_template_ids)} templates from examples")
|
||||
return imported_template_ids
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error importing templates from examples: {e}")
|
||||
return imported_template_ids
|
||||
|
||||
|
||||
async def create_default_global_template():
|
||||
"""Create default global master template (fallback if no examples found)"""
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
db_service = DatabaseService(session)
|
||||
|
||||
# Check if default template already exists
|
||||
existing = await db_service.get_global_master_template_by_name("默认商务模板")
|
||||
if existing:
|
||||
logger.info("Default global master template already exists")
|
||||
return existing.id
|
||||
|
||||
|
||||
# Create default template
|
||||
template_data = {
|
||||
"template_name": "默认商务模板",
|
||||
@@ -191,25 +289,77 @@ async def create_default_global_template():
|
||||
"is_active": True,
|
||||
"created_by": "system"
|
||||
}
|
||||
|
||||
|
||||
template = await db_service.create_global_master_template(template_data)
|
||||
logger.info(f"Created default global master template with ID: {template.id}")
|
||||
return template.id
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating default global master template: {e}")
|
||||
raise
|
||||
|
||||
async def ensure_default_template_exists():
|
||||
"""Ensure default template exists, create if not"""
|
||||
async def ensure_default_templates_exist(force_import: bool = False):
|
||||
"""Ensure default templates exist, import from examples or create fallback
|
||||
|
||||
Args:
|
||||
force_import: If True, always try to import templates regardless of existing templates
|
||||
"""
|
||||
try:
|
||||
template_id = await create_default_global_template()
|
||||
logger.info(f"Default global master template ensured with ID: {template_id}")
|
||||
return template_id
|
||||
# 检查是否已有模板(除非强制导入)
|
||||
if not force_import:
|
||||
async with AsyncSessionLocal() as session:
|
||||
db_service = DatabaseService(session)
|
||||
existing_templates = await db_service.get_all_global_master_templates(active_only=False)
|
||||
|
||||
if existing_templates:
|
||||
logger.info(f"Found {len(existing_templates)} existing templates, skipping import")
|
||||
return [template.id for template in existing_templates]
|
||||
|
||||
# 首先尝试从template_examples导入模板
|
||||
imported_ids = await import_templates_from_examples()
|
||||
|
||||
if imported_ids:
|
||||
logger.info(f"Successfully imported {len(imported_ids)} templates from examples")
|
||||
|
||||
# 检查是否有默认模板,如果没有则设置第一个导入的模板为默认
|
||||
async with AsyncSessionLocal() as session:
|
||||
db_service = DatabaseService(session)
|
||||
default_template = await db_service.get_default_global_master_template()
|
||||
|
||||
if not default_template and imported_ids:
|
||||
# 设置第一个导入的模板为默认模板
|
||||
await db_service.update_global_master_template(imported_ids[0], {"is_default": True})
|
||||
logger.info(f"Set template ID {imported_ids[0]} as default template")
|
||||
|
||||
return imported_ids
|
||||
else:
|
||||
# 如果没有成功导入任何模板,则创建默认模板
|
||||
logger.info("No templates imported from examples, creating fallback default template")
|
||||
template_id = await create_default_global_template()
|
||||
logger.info(f"Fallback default template created with ID: {template_id}")
|
||||
return [template_id] if template_id else []
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to ensure default templates exist: {e}")
|
||||
return []
|
||||
|
||||
|
||||
async def ensure_default_templates_exist_first_time():
|
||||
"""Ensure default templates exist on first time database creation"""
|
||||
return await ensure_default_templates_exist(force_import=True)
|
||||
|
||||
|
||||
async def ensure_default_template_exists():
|
||||
"""Ensure default template exists, create if not (legacy function for compatibility)"""
|
||||
try:
|
||||
template_ids = await ensure_default_templates_exist()
|
||||
if template_ids:
|
||||
return template_ids[0] # 返回第一个模板ID以保持兼容性
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to ensure default template exists: {e}")
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the script to create default template
|
||||
asyncio.run(ensure_default_template_exists())
|
||||
# Run the script to import templates from examples and create default templates
|
||||
asyncio.run(ensure_default_templates_exist())
|
||||
|
||||
+13
-5
@@ -19,7 +19,7 @@ from .api.config_api import router as config_router
|
||||
from .web import router as web_router
|
||||
from .auth import auth_router, create_auth_middleware
|
||||
from .database.database import init_db
|
||||
from .database.create_default_template import ensure_default_template_exists
|
||||
from .database.create_default_template import ensure_default_templates_exist_first_time
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
@@ -46,14 +46,22 @@ app = FastAPI(
|
||||
async def startup_event():
|
||||
"""Initialize database on startup"""
|
||||
try:
|
||||
# Check if database file exists before initialization
|
||||
import os
|
||||
db_file_path = "landppt.db" # 默认数据库文件路径
|
||||
db_exists = os.path.exists(db_file_path)
|
||||
|
||||
logger.info("Initializing database...")
|
||||
await init_db()
|
||||
logger.info("Database initialized successfully")
|
||||
|
||||
# Ensure default global master template exists
|
||||
logger.debug("Ensuring default global master template...")
|
||||
await ensure_default_template_exists()
|
||||
logger.debug("Default global master template ensured")
|
||||
# Only import templates if database file didn't exist before (first time setup)
|
||||
if not db_exists:
|
||||
logger.info("First time setup detected - importing templates from examples...")
|
||||
template_ids = await ensure_default_templates_exist_first_time()
|
||||
logger.info(f"Template initialization completed. {len(template_ids)} templates available.")
|
||||
else:
|
||||
logger.info("Database already exists - skipping template import")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize application: {e}")
|
||||
|
||||
@@ -226,11 +226,8 @@ class PDFToPPTXConverter:
|
||||
# Use SDK manager to get the correct platform directory
|
||||
platform_dir = self.sdk_manager.platform_dir
|
||||
|
||||
# For Windows, use the nested directory structure
|
||||
if self.sdk_manager.platform_name == 'windows':
|
||||
sdk_resource_dir = platform_dir / 'Lib' / 'Windows'
|
||||
else:
|
||||
sdk_resource_dir = platform_dir
|
||||
|
||||
sdk_resource_dir = platform_dir / 'Lib' / self.sdk_manager.platform_name
|
||||
|
||||
# Add resource search path for the downloaded SDK
|
||||
if sdk_resource_dir.exists():
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"template_name": "默认商务模板",
|
||||
"description": "现代简约的商务PPT模板,适用于各种商务演示场景。采用深色背景和蓝色主色调,支持多种内容类型展示。",
|
||||
"html_template": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>{{ page_title }}</title>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/js/all.min.js\"></script>\n <style>\n html {\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: #111827; \n }\n\n body {\n width: 1280px;\n height: 720px;\n margin: 0;\n padding: 0;\n position: relative;\n overflow: hidden;\n background: linear-gradient(135deg, #1e293b 0%, #334155 100%);\n font-family: 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;\n flex-shrink: 0; \n }\n \n .slide-container {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n color: white;\n position: relative;\n }\n \n .slide-header {\n padding: 40px 60px 20px 60px;\n border-bottom: 2px solid rgba(96, 165, 250, 0.3);\n }\n \n .slide-title {\n font-size: clamp(2rem, 4vw, 3.5rem);\n font-weight: bold;\n color: #60a5fa;\n margin: 0;\n line-height: 1.2;\n max-height: 80px;\n overflow: hidden;\n }\n \n .slide-content {\n flex: 1;\n padding: 30px 60px;\n display: flex;\n flex-direction: column;\n justify-content: center;\n max-height: 580px;\n overflow: hidden;\n }\n \n .content-main {\n font-size: clamp(1rem, 2.5vw, 1.4rem);\n line-height: 1.5;\n color: #e2e8f0;\n }\n \n .content-points {\n list-style: none;\n padding: 0;\n margin: 0;\n }\n \n .content-points li {\n margin-bottom: 15px;\n padding-left: 30px;\n position: relative;\n }\n \n .content-points li:before {\n content: \"▶\";\n position: absolute;\n left: 0;\n color: #60a5fa;\n font-size: 0.8em;\n }\n \n .slide-footer {\n position: absolute;\n bottom: 20px;\n right: 30px;\n font-size: 14px;\n color: #94a3b8;\n font-weight: 600;\n }\n \n .chart-container {\n max-height: 300px;\n margin: 20px 0;\n }\n \n .highlight-box {\n background: rgba(96, 165, 250, 0.1);\n border-left: 4px solid #60a5fa;\n padding: 20px;\n margin: 20px 0;\n border-radius: 0 8px 8px 0;\n }\n \n .stats-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 20px;\n margin: 20px 0;\n }\n \n .stat-card {\n background: rgba(255, 255, 255, 0.1);\n padding: 20px;\n border-radius: 8px;\n text-align: center;\n border: 1px solid rgba(96, 165, 250, 0.3);\n }\n \n .stat-number {\n font-size: 2.5rem;\n font-weight: bold;\n color: #60a5fa;\n display: block;\n }\n \n .stat-label {\n font-size: 1rem;\n color: #cbd5e1;\n margin-top: 5px;\n }\n \n @media (max-width: 1280px) {\n body {\n width: 100vw;\n height: 56.25vw;\n max-height: 100vh;\n }\n }\n </style>\n</head>\n<body>\n <div class=\"slide-container\">\n <div class=\"slide-header\">\n <h1 class=\"slide-title\">{{ main_heading }}</h1>\n </div>\n \n <div class=\"slide-content\">\n <div class=\"content-main\">\n {{ page_content }}\n </div>\n </div>\n \n <div class=\"slide-footer\">\n {{ current_page_number }} / {{ total_page_count }}\n </div>\n </div>\n</body>\n</html>",
|
||||
"tags": [
|
||||
"默认",
|
||||
"商务",
|
||||
"现代",
|
||||
"简约",
|
||||
"深色"
|
||||
],
|
||||
"is_default": false,
|
||||
"export_info": {
|
||||
"exported_at": "2025-06-28T10:11:20.488Z",
|
||||
"original_id": 1,
|
||||
"original_created_at": 1749553414.0671556
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -281,6 +281,45 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128", size = 9566 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "apryse-sdk"
|
||||
version = "11.5.0"
|
||||
source = { registry = "https://pypi.apryse.com/" }
|
||||
wheels = [
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:8a09814818ccd9743b934d50d0248bea7f3c8fffc81fd2b44c66d6df7d187a36" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-manylinux1_i686.whl", hash = "sha256:b4157ae041346d32a1e792c4a7936e44858d6722367524dc1c0e9329fca698f6" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:f9910e9853b9dc8c9d59c62f3ebd79b86d6c3a78a2b6edecf381207f2ed27bc8" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-manylinux2010_i686.whl", hash = "sha256:50118b2432dab1bb0536a1faa5149cad929a2600285635171e350777e702b962" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-manylinux2010_x86_64.whl", hash = "sha256:e3a654d8503202cbf70d5bb9c1cf5675ace75f1bdffd1edae9f1c93572471f8d" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:561df95e206a306e61330f6d50b3799fa2c2d6a6298201bb9c33d7ecf7c19431" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-manylinux2014_i686.whl", hash = "sha256:4029cf045709e9420acebdcf6e62294ddbb6d59c04e785799765a2e99f6ed64e" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:db3e96b2248598d2b9238e4f437f97e0787354165b04429182cc02b4d9afc9e7" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:83a93c832f38c4e78ca4d392cc7c72733de06136432c2a17319ad8ba9d4ae4cc" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-win32.whl", hash = "sha256:4d5b634174f7f8b1f3027b95a8ade7eab2b60053e97dbcf612ae0f45dc4119b9" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:147096849a58caa85c95cf4c78071aa58831b1ef217cf63c28798cf86f066070" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:d1ed466eab5fbaeed11755a15f5b12ecf13628201ef4254480ab9cf6294ccd87" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-manylinux1_i686.whl", hash = "sha256:c8736d0e5654127196966fc47dcfeb5e1e4052eb27d7259756e221fdb73349e3" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:ae446320f045fffd23f46be9138f2f83e40e5f76259f4f5394195359727df647" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-manylinux2010_i686.whl", hash = "sha256:f3fe916b02dbaf14a9fd466b2b4ac2c8ff50a4dd67ee9ac8a1fe6c63fc7473de" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-manylinux2010_x86_64.whl", hash = "sha256:8aa123162e448d3bc7db81d007817618b36205d0f40743cba32b616ecf0d08aa" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:1a067e0fb7d086a9504b87bc988742aaf1cf1b0aa4d6ea336b8149860e8e8e36" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-manylinux2014_i686.whl", hash = "sha256:dd9c097548f88a61edc018af3396a619c74369bcf94c48b473f7094d2d923234" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:9560d061f97351e4abfd2181f1c8a7357a83efb715f7c0fea8f8245f60dc637c" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf67327376e8284e953400066fc4101e30e867126f447e77cb2826f43e85c732" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-win32.whl", hash = "sha256:fdc0b83d2441ca2620d976b314e8b9095f7e26d14e9d6662350d86c72d47ea4b" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:21671b950783d950aaa512748470b7a51ef40367f6a61601891a971fc657ff3f" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:122221a84124d91f2b7e611c4416a590e183aead417a752e0348c151b36e263e" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp313-cp313-manylinux1_i686.whl", hash = "sha256:4548c6fad12ade57048990632959874b8f20bf7bc704a47182b3c4ec3cd0d053" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:287b56457b663e10f4368f3d4a34379988a43fdfbfc39eb8756ca40be0b078a6" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp313-cp313-manylinux2010_i686.whl", hash = "sha256:ee9ba714ecea40f84bb6b56bf6e8e8c2e17a5938ed66b082f2847be219e853cd" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp313-cp313-manylinux2010_x86_64.whl", hash = "sha256:8986d2f9ef74cb983d3da2479cdd3b0671027d7900572b9b8e41525094fba826" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:9aa52079abfd15158930e74a7d6713c208e5b99448f2ea86daac8eb573c1599a" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp313-cp313-manylinux2014_i686.whl", hash = "sha256:a2b09004b91be922d28019f4e5b2b8f90d8ebe472f5e830dce5b89e85e8a8e60" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:cb03277d259501de0f78c8ea45858298740dfa0a5131a6785afbca25f8896bf7" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp313-cp313-win32.whl", hash = "sha256:c1d071f7050c5e7e0ba2ea008f8e125e68446cf2d9cdf8ee9ddfb029fef91037" },
|
||||
{ url = "https://pypi.apryse.com/apryse-sdk/apryse_sdk-11.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:2d00590624bc523daba5521b3117218963a4d9ccb340a353ee14154df27e0c93" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "25.3.0"
|
||||
@@ -1608,6 +1647,7 @@ dependencies = [
|
||||
{ name = "aiosqlite" },
|
||||
{ name = "alembic" },
|
||||
{ name = "anthropic" },
|
||||
{ name = "apryse-sdk" },
|
||||
{ name = "beautifulsoup4" },
|
||||
{ name = "chardet" },
|
||||
{ name = "click" },
|
||||
@@ -1633,7 +1673,6 @@ dependencies = [
|
||||
{ name = "pdfkit" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-settings" },
|
||||
{ name = "pypdf" },
|
||||
{ name = "pypdf2" },
|
||||
{ name = "pyppeteer" },
|
||||
{ name = "python-docx" },
|
||||
@@ -1657,6 +1696,7 @@ requires-dist = [
|
||||
{ name = "aiosqlite", specifier = ">=0.19.0" },
|
||||
{ name = "alembic", specifier = ">=1.13.0" },
|
||||
{ name = "anthropic", specifier = ">=0.7.0" },
|
||||
{ name = "apryse-sdk", specifier = ">=11.5.0" },
|
||||
{ name = "beautifulsoup4", specifier = ">=4.12.0" },
|
||||
{ name = "chardet", specifier = ">=5.0.0" },
|
||||
{ name = "click", specifier = ">=8.0.0" },
|
||||
@@ -1671,7 +1711,6 @@ requires-dist = [
|
||||
{ name = "langchain-ollama", specifier = ">=0.1.0" },
|
||||
{ name = "langchain-openai", specifier = ">=0.1.0" },
|
||||
{ name = "langgraph", specifier = ">=0.1.0" },
|
||||
{ name = "markdown", specifier = ">=3.5.0" },
|
||||
{ name = "markdown", specifier = ">=3.5.1" },
|
||||
{ name = "markitdown", extras = ["all"], specifier = ">=0.1.2" },
|
||||
{ name = "mineru", extras = ["core"], specifier = ">=2.0.6" },
|
||||
@@ -1681,10 +1720,8 @@ requires-dist = [
|
||||
{ name = "pandas", specifier = ">=2.0.0" },
|
||||
{ name = "passlib", extras = ["bcrypt"], specifier = ">=1.7.4" },
|
||||
{ name = "pdfkit", specifier = ">=1.0.0" },
|
||||
{ name = "pydantic", specifier = ">=2.0.0" },
|
||||
{ name = "pydantic", specifier = ">=2.5.0" },
|
||||
{ name = "pydantic-settings", specifier = ">=2.0.0" },
|
||||
{ name = "pypdf", specifier = ">=4.0.0" },
|
||||
{ name = "pypdf2", specifier = ">=3.0.1" },
|
||||
{ name = "pyppeteer", specifier = ">=1.0.2" },
|
||||
{ name = "python-docx", specifier = ">=1.1.0" },
|
||||
@@ -2443,7 +2480,7 @@ name = "nvidia-cudnn-cu12"
|
||||
version = "9.5.1.17"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "nvidia-cublas-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
|
||||
{ name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/99/93/a201a12d3ec1caa8c6ac34c1c2f9eeb696b886f0c36ff23c638b46603bd0/nvidia_cudnn_cu12-9.5.1.17-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9fd4584468533c61873e5fda8ca41bac3a38bcb2d12350830c69b0a96a7e4def", size = 570523509 },
|
||||
@@ -2455,7 +2492,7 @@ name = "nvidia-cufft-cu12"
|
||||
version = "11.3.0.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
|
||||
{ name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/37/c50d2b2f2c07e146776389e3080f4faf70bcc4fa6e19d65bb54ca174ebc3/nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d16079550df460376455cba121db6564089176d9bac9e4f360493ca4741b22a6", size = 200164144 },
|
||||
@@ -2489,9 +2526,9 @@ name = "nvidia-cusolver-cu12"
|
||||
version = "11.7.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "nvidia-cublas-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
|
||||
{ name = "nvidia-cusparse-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
|
||||
{ name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
|
||||
{ name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" },
|
||||
{ name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" },
|
||||
{ name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/93/17/dbe1aa865e4fdc7b6d4d0dd308fdd5aaab60f939abfc0ea1954eac4fb113/nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0ce237ef60acde1efc457335a2ddadfd7610b892d94efee7b776c64bb1cac9e0", size = 157833628 },
|
||||
@@ -2505,7 +2542,7 @@ name = "nvidia-cusparse-cu12"
|
||||
version = "12.5.4.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
|
||||
{ name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/eb/6681efd0aa7df96b4f8067b3ce7246833dd36830bb4cec8896182773db7d/nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d25b62fb18751758fe3c93a4a08eff08effedfe4edf1c6bb5afd0890fe88f887", size = 216451147 },
|
||||
@@ -4164,7 +4201,7 @@ name = "triton"
|
||||
version = "3.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "setuptools", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
|
||||
{ name = "setuptools", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/21/2f/3e56ea7b58f80ff68899b1dbe810ff257c9d177d288c6b0f55bf2fe4eb50/triton-3.3.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b31e3aa26f8cb3cc5bf4e187bf737cbacf17311e1112b781d4a059353dfd731b", size = 155689937 },
|
||||
|
||||
Reference in New Issue
Block a user