maque 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. maque/__init__.py +30 -0
  2. maque/__main__.py +926 -0
  3. maque/ai_platform/__init__.py +0 -0
  4. maque/ai_platform/crawl.py +45 -0
  5. maque/ai_platform/metrics.py +258 -0
  6. maque/ai_platform/nlp_preprocess.py +67 -0
  7. maque/ai_platform/webpage_screen_shot.py +195 -0
  8. maque/algorithms/__init__.py +78 -0
  9. maque/algorithms/bezier.py +15 -0
  10. maque/algorithms/bktree.py +117 -0
  11. maque/algorithms/core.py +104 -0
  12. maque/algorithms/hilbert.py +16 -0
  13. maque/algorithms/rate_function.py +92 -0
  14. maque/algorithms/transform.py +27 -0
  15. maque/algorithms/trie.py +272 -0
  16. maque/algorithms/utils.py +63 -0
  17. maque/algorithms/video.py +587 -0
  18. maque/api/__init__.py +1 -0
  19. maque/api/common.py +110 -0
  20. maque/api/fetch.py +26 -0
  21. maque/api/static/icon.png +0 -0
  22. maque/api/static/redoc.standalone.js +1782 -0
  23. maque/api/static/swagger-ui-bundle.js +3 -0
  24. maque/api/static/swagger-ui.css +3 -0
  25. maque/cli/__init__.py +1 -0
  26. maque/cli/clean_invisible_chars.py +324 -0
  27. maque/cli/core.py +34 -0
  28. maque/cli/groups/__init__.py +26 -0
  29. maque/cli/groups/config.py +205 -0
  30. maque/cli/groups/data.py +615 -0
  31. maque/cli/groups/doctor.py +259 -0
  32. maque/cli/groups/embedding.py +222 -0
  33. maque/cli/groups/git.py +29 -0
  34. maque/cli/groups/help.py +410 -0
  35. maque/cli/groups/llm.py +223 -0
  36. maque/cli/groups/mcp.py +241 -0
  37. maque/cli/groups/mllm.py +1795 -0
  38. maque/cli/groups/mllm_simple.py +60 -0
  39. maque/cli/groups/quant.py +210 -0
  40. maque/cli/groups/service.py +490 -0
  41. maque/cli/groups/system.py +570 -0
  42. maque/cli/mllm_run.py +1451 -0
  43. maque/cli/script.py +52 -0
  44. maque/cli/tree.py +49 -0
  45. maque/clustering/__init__.py +52 -0
  46. maque/clustering/analyzer.py +347 -0
  47. maque/clustering/clusterers.py +464 -0
  48. maque/clustering/sampler.py +134 -0
  49. maque/clustering/visualizer.py +205 -0
  50. maque/constant.py +13 -0
  51. maque/core.py +133 -0
  52. maque/cv/__init__.py +1 -0
  53. maque/cv/image.py +219 -0
  54. maque/cv/utils.py +68 -0
  55. maque/cv/video/__init__.py +3 -0
  56. maque/cv/video/keyframe_extractor.py +368 -0
  57. maque/embedding/__init__.py +43 -0
  58. maque/embedding/base.py +56 -0
  59. maque/embedding/multimodal.py +308 -0
  60. maque/embedding/server.py +523 -0
  61. maque/embedding/text.py +311 -0
  62. maque/git/__init__.py +24 -0
  63. maque/git/pure_git.py +912 -0
  64. maque/io/__init__.py +29 -0
  65. maque/io/core.py +38 -0
  66. maque/io/ops.py +194 -0
  67. maque/llm/__init__.py +111 -0
  68. maque/llm/backend.py +416 -0
  69. maque/llm/base.py +411 -0
  70. maque/llm/server.py +366 -0
  71. maque/mcp_server.py +1096 -0
  72. maque/mllm_data_processor_pipeline/__init__.py +17 -0
  73. maque/mllm_data_processor_pipeline/core.py +341 -0
  74. maque/mllm_data_processor_pipeline/example.py +291 -0
  75. maque/mllm_data_processor_pipeline/steps/__init__.py +56 -0
  76. maque/mllm_data_processor_pipeline/steps/data_alignment.py +267 -0
  77. maque/mllm_data_processor_pipeline/steps/data_loader.py +172 -0
  78. maque/mllm_data_processor_pipeline/steps/data_validation.py +304 -0
  79. maque/mllm_data_processor_pipeline/steps/format_conversion.py +411 -0
  80. maque/mllm_data_processor_pipeline/steps/mllm_annotation.py +331 -0
  81. maque/mllm_data_processor_pipeline/steps/mllm_refinement.py +446 -0
  82. maque/mllm_data_processor_pipeline/steps/result_validation.py +501 -0
  83. maque/mllm_data_processor_pipeline/web_app.py +317 -0
  84. maque/nlp/__init__.py +14 -0
  85. maque/nlp/ngram.py +9 -0
  86. maque/nlp/parser.py +63 -0
  87. maque/nlp/risk_matcher.py +543 -0
  88. maque/nlp/sentence_splitter.py +202 -0
  89. maque/nlp/simple_tradition_cvt.py +31 -0
  90. maque/performance/__init__.py +21 -0
  91. maque/performance/_measure_time.py +70 -0
  92. maque/performance/_profiler.py +367 -0
  93. maque/performance/_stat_memory.py +51 -0
  94. maque/pipelines/__init__.py +15 -0
  95. maque/pipelines/clustering.py +252 -0
  96. maque/quantization/__init__.py +42 -0
  97. maque/quantization/auto_round.py +120 -0
  98. maque/quantization/base.py +145 -0
  99. maque/quantization/bitsandbytes.py +127 -0
  100. maque/quantization/llm_compressor.py +102 -0
  101. maque/retriever/__init__.py +35 -0
  102. maque/retriever/chroma.py +654 -0
  103. maque/retriever/document.py +140 -0
  104. maque/retriever/milvus.py +1140 -0
  105. maque/table_ops/__init__.py +1 -0
  106. maque/table_ops/core.py +133 -0
  107. maque/table_viewer/__init__.py +4 -0
  108. maque/table_viewer/download_assets.py +57 -0
  109. maque/table_viewer/server.py +698 -0
  110. maque/table_viewer/static/element-plus-icons.js +5791 -0
  111. maque/table_viewer/static/element-plus.css +1 -0
  112. maque/table_viewer/static/element-plus.js +65236 -0
  113. maque/table_viewer/static/main.css +268 -0
  114. maque/table_viewer/static/main.js +669 -0
  115. maque/table_viewer/static/vue.global.js +18227 -0
  116. maque/table_viewer/templates/index.html +401 -0
  117. maque/utils/__init__.py +56 -0
  118. maque/utils/color.py +68 -0
  119. maque/utils/color_string.py +45 -0
  120. maque/utils/compress.py +66 -0
  121. maque/utils/constant.py +183 -0
  122. maque/utils/core.py +261 -0
  123. maque/utils/cursor.py +143 -0
  124. maque/utils/distance.py +58 -0
  125. maque/utils/docker.py +96 -0
  126. maque/utils/downloads.py +51 -0
  127. maque/utils/excel_helper.py +542 -0
  128. maque/utils/helper_metrics.py +121 -0
  129. maque/utils/helper_parser.py +168 -0
  130. maque/utils/net.py +64 -0
  131. maque/utils/nvidia_stat.py +140 -0
  132. maque/utils/ops.py +53 -0
  133. maque/utils/packages.py +31 -0
  134. maque/utils/path.py +57 -0
  135. maque/utils/tar.py +260 -0
  136. maque/utils/untar.py +129 -0
  137. maque/web/__init__.py +0 -0
  138. maque/web/image_downloader.py +1410 -0
  139. maque-0.2.1.dist-info/METADATA +450 -0
  140. maque-0.2.1.dist-info/RECORD +143 -0
  141. maque-0.2.1.dist-info/WHEEL +4 -0
  142. maque-0.2.1.dist-info/entry_points.txt +3 -0
  143. maque-0.2.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,401 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Sparrow Table Viewer</title>
7
+ <script src="/static/vue.global.js"></script>
8
+ <script src="/static/element-plus.js"></script>
9
+ <script src="/static/element-plus-icons.js"></script>
10
+ <link rel="stylesheet" href="/static/element-plus.css" />
11
+ <link rel="stylesheet" href="/static/main.css" />
12
+ </head>
13
+ <body>
14
+ {% raw %}
15
+ <div id="app">
16
+ <div class="main-container">
17
+ <!-- 头部 -->
18
+ <div class="header">
19
+ <div style="display: flex; align-items: center; gap: 16px;">
20
+ <h1 style="margin: 0; font-size: 20px; color: #303133;">
21
+ 📊 Sparrow Table Viewer
22
+ </h1>
23
+ <el-tag v-if="tableInfo" type="info">{{ tableInfo.file_path }}</el-tag>
24
+ </div>
25
+ <div style="display: flex; gap: 12px;">
26
+ <el-button @click="showUploadDialog = true" type="success" size="small">
27
+ 上传文件
28
+ </el-button>
29
+ <el-button @click="resetTable" type="warning" size="small">
30
+ 重置
31
+ </el-button>
32
+ <el-button @click="saveTable" type="primary" size="small">
33
+ 保存
34
+ </el-button>
35
+ </div>
36
+ </div>
37
+
38
+ <!-- 内容区域 -->
39
+ <div class="content">
40
+ <!-- 工具栏 -->
41
+ <div class="toolbar">
42
+ <el-button @click="refreshData" size="small" :loading="loading">
43
+ 刷新数据
44
+ </el-button>
45
+
46
+ <el-divider direction="vertical"></el-divider>
47
+
48
+ <span style="color: #606266; font-size: 14px;">每页显示:</span>
49
+ <el-select v-model="pagination.pageSize" @change="loadTableData" size="small" style="width: 100px;">
50
+ <el-option :value="50" label="50"></el-option>
51
+ <el-option :value="100" label="100"></el-option>
52
+ <el-option :value="200" label="200"></el-option>
53
+ <el-option :value="500" label="500"></el-option>
54
+ </el-select>
55
+
56
+ <el-divider direction="vertical"></el-divider>
57
+
58
+ <el-button @click="showFilterDialog = true" size="small" type="info">
59
+ 行筛选 ({{ activeFilters.length }})
60
+ </el-button>
61
+
62
+ <el-button @click="clearFilters" size="small" v-if="activeFilters.length > 0">
63
+ 清除行筛选
64
+ </el-button>
65
+
66
+ <el-divider direction="vertical"></el-divider>
67
+
68
+ <el-button @click="showColumnDialog = true" size="small" type="success">
69
+ 列显示 ({{ visibleColumns.length }}/{{ allColumns.length }})
70
+ </el-button>
71
+
72
+ <el-button @click="resetColumns" size="small" v-if="visibleColumns.length < allColumns.length">
73
+ 显示全部列
74
+ </el-button>
75
+
76
+ <el-divider direction="vertical" v-if="tableInfo && tableInfo.image_columns && tableInfo.image_columns.length"></el-divider>
77
+
78
+ <!-- 图像设置 -->
79
+ <div v-if="tableInfo && tableInfo.image_columns && tableInfo.image_columns.length" style="display: flex; align-items: center; gap: 16px;">
80
+ <!-- 图像尺寸设置 -->
81
+ <div style="display: flex; align-items: center; gap: 8px;">
82
+ <span style="color: #606266; font-size: 14px;">图像尺寸:</span>
83
+ <el-select v-model="imageSize" @change="onImageSizeChange" size="small" style="width: 140px;">
84
+ <el-option value="small" label="小 (80x60)"></el-option>
85
+ <el-option value="medium" label="中 (120x90)"></el-option>
86
+ <el-option value="large" label="大 (160x120)"></el-option>
87
+ <el-option value="xlarge" label="超大 (200x150)"></el-option>
88
+ <el-option value="xxlarge" label="最大 (400x300)"></el-option>
89
+ </el-select>
90
+ </div>
91
+
92
+ <!-- 分隔符设置 -->
93
+ <div style="display: flex; align-items: center; gap: 8px;">
94
+ <span style="color: #606266; font-size: 14px;">分隔符:</span>
95
+ <el-select v-model="imageSeparator" @change="onSeparatorChange" @update:model-value="onSeparatorChange" size="small" style="width: 120px;">
96
+ <el-option value="auto" label="自动检测"></el-option>
97
+ <el-option value="semicolon" label="分号 ;"></el-option>
98
+ <el-option value="newline" label="换行符"></el-option>
99
+ <el-option value="custom" label="自定义"></el-option>
100
+ </el-select>
101
+
102
+ <!-- 自定义分隔符输入 -->
103
+ <el-input
104
+ v-if="imageSeparator === 'custom'"
105
+ v-model="customSeparator"
106
+ @change="onSeparatorChange"
107
+ placeholder="输入分隔符"
108
+ size="small"
109
+ style="width: 100px;"
110
+ ></el-input>
111
+ </div>
112
+ </div>
113
+ </div>
114
+
115
+ <!-- 统计信息 -->
116
+ <div class="stats-info" v-if="tableInfo">
117
+ <span style="margin-right: 24px;">
118
+ <strong>总行数:</strong> {{ tableData.total || 0 }} 行
119
+ </span>
120
+ <span style="margin-right: 24px;">
121
+ <strong>显示列数:</strong> {{ visibleColumns.length }}/{{ allColumns.length }} 列
122
+ </span>
123
+ <span v-if="tableInfo.image_columns && tableInfo.image_columns.length">
124
+ <strong>图片列:</strong> {{ tableInfo.image_columns.join(', ') }}
125
+ </span>
126
+ </div>
127
+
128
+ <!-- 表格容器 -->
129
+ <div class="table-container">
130
+ <el-table
131
+ :data="tableData.data"
132
+ stripe
133
+ border
134
+ :loading="loading"
135
+ style="width: 100%;"
136
+ max-height="calc(100vh - 320px)"
137
+ size="small"
138
+ >
139
+ <el-table-column
140
+ v-for="column in tableColumns"
141
+ :key="column"
142
+ :prop="column"
143
+ :label="column"
144
+ :width="getColumnWidth(column)"
145
+ :sortable="false"
146
+ show-overflow-tooltip
147
+ >
148
+ <template #header="{ column: headerColumn }">
149
+ <div style="display: flex; align-items: center; gap: 8px; justify-content: space-between; width: 100%;">
150
+ <span style="flex: 1;">{{ headerColumn.label }}</span>
151
+ <div style="display: flex; align-items: center; gap: 4px;">
152
+ <!-- 排序按钮 -->
153
+ <el-button-group size="small">
154
+ <el-button
155
+ @click.stop="handleSort(headerColumn.label, 'asc')"
156
+ :type="sortConfig.prop === headerColumn.label && sortConfig.order === 'ascending' ? 'primary' : ''"
157
+ size="small"
158
+ style="padding: 2px 4px; font-size: 10px;"
159
+ title="升序"
160
+ >
161
+
162
+ </el-button>
163
+ <el-button
164
+ @click.stop="handleSort(headerColumn.label, 'desc')"
165
+ :type="sortConfig.prop === headerColumn.label && sortConfig.order === 'descending' ? 'primary' : ''"
166
+ size="small"
167
+ style="padding: 2px 4px; font-size: 10px;"
168
+ title="降序"
169
+ >
170
+
171
+ </el-button>
172
+ </el-button-group>
173
+
174
+ <!-- 筛选按钮 -->
175
+ <el-button
176
+ @click.stop="addColumnFilter(headerColumn.label)"
177
+ size="small"
178
+ type="text"
179
+ style="padding: 2px 4px; font-size: 10px;"
180
+ title="筛选"
181
+ >
182
+ 🔍
183
+ </el-button>
184
+ </div>
185
+ </div>
186
+ </template>
187
+
188
+ <template #default="scope">
189
+ <div v-if="isImageColumn(column)">
190
+ <div v-if="scope.row[column] && scope.row[column].paths && scope.row[column].paths.length > 0" class="multi-images-container">
191
+ <template v-for="(imagePath, index) in scope.row[column].paths" :key="index">
192
+ <!-- 图像加载成功时显示图片 -->
193
+ <img
194
+ v-if="isImageLoaded(imagePath)"
195
+ :src="`/api/image/proxy?url=${encodeURIComponent(imagePath)}`"
196
+ :alt="imagePath"
197
+ class="multi-image-item"
198
+ @click="showImageDialog(imagePath, scope.row[column].paths, index)"
199
+ />
200
+ <!-- 图像未加载成功时显示原始URL字符串 -->
201
+ <div
202
+ v-else
203
+ style="color: #666; font-size: 12px; word-break: break-all; line-height: 1.4; cursor: pointer; margin-right: 8px; padding: 4px;"
204
+ @click="showImageDialog(imagePath, scope.row[column].paths, index)"
205
+ >
206
+ {{ imagePath }}
207
+ </div>
208
+ <!-- 隐藏的图片元素用于检测加载状态 -->
209
+ <img
210
+ v-if="!isImageLoaded(imagePath)"
211
+ :src="`/api/image/proxy?url=${encodeURIComponent(imagePath)}`"
212
+ style="display: none;"
213
+ @load="onImageLoadSuccess(imagePath)"
214
+ @error="onImageLoadError(imagePath)"
215
+ />
216
+ </template>
217
+ </div>
218
+ <div v-else style="color: #666; font-size: 12px; word-break: break-all; line-height: 1.4; padding: 4px;">
219
+ {{ scope.row[column] && scope.row[column].original ? scope.row[column].original : (scope.row[column] || '') }}
220
+ </div>
221
+ </div>
222
+ <div v-else>
223
+ <input
224
+ v-if="editingCell && editingCell.row === scope.$index && editingCell.column === column"
225
+ v-model="editingValue"
226
+ @blur="saveCell(scope.row._index, column)"
227
+ @keyup.enter="saveCell(scope.row._index, column)"
228
+ @keyup.escape="cancelEdit"
229
+ class="cell-editor"
230
+ ref="cellInput"
231
+ />
232
+ <span
233
+ v-else
234
+ @dblclick="startEdit(scope.$index, column, scope.row[column])"
235
+ style="cursor: pointer; display: block; min-height: 20px;"
236
+ >
237
+ {{ scope.row[column] || '' }}
238
+ </span>
239
+ </div>
240
+ </template>
241
+ </el-table-column>
242
+ </el-table>
243
+
244
+ <!-- 分页 -->
245
+ <div style="margin-top: 20px; display: flex; justify-content: center;">
246
+ <el-pagination
247
+ v-model:current-page="pagination.currentPage"
248
+ v-model:page-size="pagination.pageSize"
249
+ :page-sizes="[50, 100, 200, 500]"
250
+ layout="total, sizes, prev, pager, next, jumper"
251
+ :total="tableData.total"
252
+ @size-change="handleSizeChange"
253
+ @current-change="handleCurrentChange"
254
+ />
255
+ </div>
256
+ </div>
257
+ </div>
258
+ </div>
259
+
260
+ <!-- 筛选对话框 -->
261
+ <el-dialog v-model="showFilterDialog" title="高级筛选" width="600px">
262
+ <div v-for="(filter, index) in filterConfigs" :key="index" style="margin-bottom: 16px;">
263
+ <el-row :gutter="12">
264
+ <el-col :span="6">
265
+ <el-select v-model="filter.column" placeholder="选择列">
266
+ <el-option v-for="col in tableColumns" :key="col" :value="col" :label="col"></el-option>
267
+ </el-select>
268
+ </el-col>
269
+ <el-col :span="6">
270
+ <el-select v-model="filter.operator" placeholder="操作符">
271
+ <el-option value="contains" label="包含"></el-option>
272
+ <el-option value="eq" label="等于"></el-option>
273
+ <el-option value="ne" label="不等于"></el-option>
274
+ <el-option value="startswith" label="开头是"></el-option>
275
+ <el-option value="endswith" label="结尾是"></el-option>
276
+ <el-option value="gt" label="大于"></el-option>
277
+ <el-option value="lt" label="小于"></el-option>
278
+ <el-option value="ge" label="大于等于"></el-option>
279
+ <el-option value="le" label="小于等于"></el-option>
280
+ </el-select>
281
+ </el-col>
282
+ <el-col :span="8">
283
+ <el-input v-model="filter.value" placeholder="筛选值"></el-input>
284
+ </el-col>
285
+ <el-col :span="4">
286
+ <el-button @click="removeFilter(index)" type="danger" size="small">删除</el-button>
287
+ </el-col>
288
+ </el-row>
289
+ </div>
290
+
291
+ <el-button @click="addFilter" type="primary" size="small">添加筛选条件</el-button>
292
+
293
+ <template #footer>
294
+ <el-button @click="showFilterDialog = false">取消</el-button>
295
+ <el-button @click="applyFilters" type="primary">应用筛选</el-button>
296
+ </template>
297
+ </el-dialog>
298
+
299
+ <!-- 列显示管理对话框 -->
300
+ <el-dialog v-model="showColumnDialog" title="列显示管理" width="500px">
301
+ <div style="margin-bottom: 16px;">
302
+ <el-button @click="selectAllColumns" size="small" type="primary">全选</el-button>
303
+ <el-button @click="selectNoColumns" size="small">全不选</el-button>
304
+ <span style="margin-left: 16px; color: #666;">
305
+ 已选择 {{ visibleColumns.length }} / {{ allColumns.length }} 列
306
+ </span>
307
+ </div>
308
+
309
+ <div style="max-height: 400px; overflow-y: auto; border: 1px solid #ddd; padding: 12px; border-radius: 4px;">
310
+ <el-row :gutter="12">
311
+ <el-col :span="12" v-for="column in allColumns" :key="column" style="margin-bottom: 8px;">
312
+ <el-checkbox
313
+ :model-value="visibleColumns.includes(column)"
314
+ @change="toggleColumn(column)"
315
+ style="width: 100%;"
316
+ >
317
+ <span :style="{ fontWeight: tableInfo && tableInfo.image_columns && tableInfo.image_columns.includes(column) ? 'bold' : 'normal', color: tableInfo && tableInfo.image_columns && tableInfo.image_columns.includes(column) ? '#409eff' : '' }">
318
+ {{ column }}
319
+ <el-tag v-if="tableInfo && tableInfo.image_columns && tableInfo.image_columns.includes(column)" size="small" type="primary">图片</el-tag>
320
+ </span>
321
+ </el-checkbox>
322
+ </el-col>
323
+ </el-row>
324
+ </div>
325
+
326
+ <template #footer>
327
+ <el-button @click="showColumnDialog = false">取消</el-button>
328
+ <el-button @click="resetColumns" type="warning">重置</el-button>
329
+ <el-button @click="applyColumnFilter" type="primary" :disabled="visibleColumns.length === 0">应用</el-button>
330
+ </template>
331
+ </el-dialog>
332
+
333
+ <!-- 图片查看对话框 -->
334
+ <el-dialog v-model="showImagePreview" :title="`${currentImageIndex + 1}/${currentImageList.length} - ${currentImageUrl}`" width="90%">
335
+ <div style="position: relative; text-align: center;">
336
+ <!-- 左箭头按钮 -->
337
+ <el-button
338
+ v-if="currentImageList.length > 1 && currentImageIndex > 0"
339
+ @click="showPreviousImage"
340
+ type="primary"
341
+ size="large"
342
+ circle
343
+ style="position: absolute; left: 20px; top: 50%; transform: translateY(-50%); z-index: 10;"
344
+ >
345
+
346
+ </el-button>
347
+
348
+ <!-- 图片 -->
349
+ <img
350
+ :src="`/api/image/proxy?url=${encodeURIComponent(currentImageUrl)}`"
351
+ style="max-width: 100%; max-height: 100vh; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);"
352
+ @error="handleImageError"
353
+ />
354
+
355
+ <!-- 右箭头按钮 -->
356
+ <el-button
357
+ v-if="currentImageList.length > 1 && currentImageIndex < currentImageList.length - 1"
358
+ @click="showNextImage"
359
+ type="primary"
360
+ size="large"
361
+ circle
362
+ style="position: absolute; right: 20px; top: 50%; transform: translateY(-50%); z-index: 10;"
363
+ >
364
+
365
+ </el-button>
366
+ </div>
367
+ </el-dialog>
368
+
369
+ <!-- 文件上传对话框 -->
370
+ <el-dialog v-model="showUploadDialog" title="上传表格文件" width="600px">
371
+ <div class="upload-area"
372
+ @click="triggerFileInput"
373
+ @drop="handleFileDrop"
374
+ @dragover="handleDragOver"
375
+ @dragleave="handleDragLeave"
376
+ :class="{ 'dragover': isDragOver }">
377
+ <div class="upload-icon">📁</div>
378
+ <div class="upload-text">
379
+ <div>点击选择文件或拖拽文件到此处</div>
380
+ <div class="upload-hint">支持 .xlsx, .xls, .csv 格式</div>
381
+ </div>
382
+ </div>
383
+
384
+ <input type="file"
385
+ ref="fileInput"
386
+ @change="handleFileSelect"
387
+ accept=".xlsx,.xls,.csv"
388
+ style="display: none;">
389
+
390
+ <template #footer>
391
+ <span class="dialog-footer">
392
+ <el-button @click="showUploadDialog = false">取消</el-button>
393
+ </span>
394
+ </template>
395
+ </el-dialog>
396
+ </div>
397
+ {% endraw %}
398
+
399
+ <script src="/static/main.js"></script>
400
+ </body>
401
+ </html>
@@ -0,0 +1,56 @@
1
+ """
2
+ 工具模块 - 通用工具和辅助功能
3
+
4
+ 整合了各种实用工具:颜色处理、字符串操作、距离计算、文件操作等
5
+ """
6
+
7
+ # 基础工具(仅依赖标准库或核心依赖)
8
+ try:
9
+ from .compress import *
10
+ from .cursor import *
11
+ from .net import *
12
+ from .time import *
13
+ from .distance import *
14
+ from .ops import * # string ops
15
+ from .tar import *
16
+ from .untar import *
17
+ except ImportError:
18
+ pass # 静默处理,避免启动时警告
19
+
20
+ # 需要 pandas 的模块(可选)
21
+ try:
22
+ from .excel_helper import *
23
+ from .helper_metrics import *
24
+ from .helper_parser import *
25
+ except ImportError:
26
+ pass # pandas 未安装时静默跳过
27
+
28
+ # 核心工具(可能有循环依赖)
29
+ try:
30
+ from .core import async_retry # 只导入关键函数
31
+ except ImportError:
32
+ # 简单的备用实现
33
+ def async_retry(retry_times=3, retry_delay=1.0):
34
+ def decorator(func):
35
+ return func
36
+ return decorator
37
+
38
+ # 颜色工具(可能有复杂依赖)
39
+ try:
40
+ from .color import *
41
+ from .constant import * # color constants
42
+ from .color_string import *
43
+ except ImportError:
44
+ pass
45
+
46
+ # 路径工具
47
+ try:
48
+ from .path import rel_to_abs, rel_path_join, ls, add_env_path
49
+ relp = rel_to_abs # alias
50
+ except ImportError:
51
+ pass
52
+
53
+ __all__ = [
54
+ 'async_retry',
55
+ # 其他具体导出项将根据实际模块内容确定
56
+ ]
maque/utils/color.py ADDED
@@ -0,0 +1,68 @@
1
+ from colour import Color
2
+ import numpy as np
3
+ from . import constant as _color_const
4
+
5
+
6
+ def color_to_rgb(color):
7
+ if isinstance(color, str):
8
+ return hex_to_rgb(color)
9
+ elif isinstance(color, Color):
10
+ return np.array(color.get_rgb())
11
+ elif isinstance(color, (tuple, list, np.ndarray)):
12
+
13
+ if isinstance(color[0], (int, np.int32, np.int64)):
14
+ return np.array(color) / 255
15
+ elif isinstance(color[0], (float, np.float32, np.float64)):
16
+ return np.array(color)
17
+ else:
18
+ raise Exception(f"Invalid color type: {type(color[0])}")
19
+
20
+ else:
21
+ raise Exception(f"Invalid color type: {color}")
22
+
23
+
24
+ def color_to_rgba(color, alpha=1):
25
+ return np.array([*color_to_rgb(color), alpha])
26
+
27
+
28
+ def rgb_to_color(rgb):
29
+ try:
30
+ return Color(rgb=rgb)
31
+ except ValueError:
32
+ return Color(_color_const.WHITE)
33
+
34
+
35
+ def rgba_to_color(rgba):
36
+ return rgb_to_color(rgba[:3])
37
+
38
+
39
+ def rgb_to_hex(rgb):
40
+ return "#" + "".join(
41
+ hex(int_x // 16)[2] + hex(int_x % 16)[2]
42
+ for x in rgb
43
+ for int_x in [int(255 * x)]
44
+ )
45
+
46
+
47
+ def hex_to_rgb(hex_code):
48
+ hex_part = hex_code[1:]
49
+ if len(hex_part) == 3:
50
+ hex_part = "".join([2 * c for c in hex_part])
51
+ return np.array([int(hex_part[i : i + 2], 16) / 255 for i in range(0, 6, 2)])
52
+
53
+
54
+ def invert_color(color):
55
+ return rgb_to_color(1.0 - color_to_rgb(color))
56
+
57
+
58
+ def color_to_int_rgb(color):
59
+ return (255 * color_to_rgb(color)).astype("uint8")
60
+
61
+
62
+ def color_to_int_rgba(color, opacity=1.0):
63
+ alpha = int(255 * opacity)
64
+ return np.array([*color_to_int_rgb(color), alpha])
65
+
66
+
67
+ def random_color():
68
+ return Color(rgb=[np.random.random() for _ in range(3)])
@@ -0,0 +1,45 @@
1
+ from .color import color_to_int_rgb
2
+ from . import constant as color_const
3
+
4
+ CSI = "\033["
5
+ OSC = "\033]"
6
+ OFF = CSI + "0m"
7
+
8
+
9
+ def __set_rgb(RGB_fore=(240, 85, 85), SRG=0, RGB_back=None):
10
+ """Get foreground or background color chars
11
+ see https://my.oschina.net/dingdayu/blog/1537064
12
+ inputs:
13
+ RGB_fore: rgb list or tupe of foreground, e.g. [255, 0, 0]
14
+ SRG: the style of font
15
+ SRG options: see https://en.wikipedia.org/wiki/ANSI_escape_code#SGR
16
+ | 0 | Close all formats and revert to the original state
17
+ | 1 | Bold (increased intensity)
18
+ | 2 | Faint (decreased intensity)
19
+ | 3 | Italics
20
+ | 4 | Underline (single line)
21
+ | 5 | Slow Blink
22
+ | 6 | Rapid Blink
23
+ | 7 | Swap the background color with the foreground color
24
+ """
25
+ fore_color = f"{CSI}{SRG};38;2;{RGB_fore[0]};{RGB_fore[1]};{RGB_fore[2]}m"
26
+ if RGB_back is None:
27
+ back_color = ""
28
+ else:
29
+ back_color = f"{CSI}{SRG};48;2;{RGB_back[0]};{RGB_back[1]};{RGB_back[2]}m"
30
+ return fore_color + back_color
31
+
32
+
33
+ def _rgb_str(string, RGB_fore=(240, 85, 85), SRG=0, RGB_back=None):
34
+ return __set_rgb(RGB_fore, SRG, RGB_back) + string + OFF
35
+
36
+
37
+ def rgb_string(string, color=color_const.RED, **kwargs):
38
+ """Return the string with color.
39
+ :param string: The string will be colored.
40
+ :param color: can be rgb list [255, 255, 255] or hex string "#ffffff".
41
+ :param `SRG`, `RGB_back` see function `__set_grb()`
42
+ :return Colored string.
43
+ """
44
+ rgb = color_to_int_rgb(color)
45
+ return _rgb_str(string, rgb, **kwargs)
@@ -0,0 +1,66 @@
1
+ import shutil
2
+ from shutil import _find_unpack_format, _UNPACK_FORMATS
3
+ from pathlib import Path
4
+ from maque.utils.path import rel_to_abs, rel_path_join
5
+ import os
6
+
7
+
8
+ def pack(source_path: str, target_path=None, format='gztar'):
9
+ """Pack or compress files.
10
+
11
+ Parameters
12
+ ----------
13
+ source_path: str:
14
+ source path
15
+ target_path: str:
16
+ target path
17
+ format : str
18
+ `format` is the archive format: one of "zip", "tar", "gztar"(default), "bztar", or "xztar".
19
+ Or any other registered format.
20
+ """
21
+ if target_path is None:
22
+ target_path = Path(source_path).name
23
+ new_path = shutil.make_archive(target_path, format, root_dir=source_path)
24
+ print(f"target path:\n{new_path}")
25
+
26
+
27
+ def unpack(filename: str, extract_dir=None, format=None):
28
+ """Unpack or decompress files.
29
+
30
+ Parameters
31
+ ----------
32
+ filename : str
33
+ input source file
34
+ extract_dir : str | None
35
+ output dir
36
+ format : str | None
37
+ `format`is the archive format: one of "zip", "tar", "gztar", "bztar", or "xztar".
38
+ If not provided, unpack_archive will use the filename extension.
39
+ """
40
+ name_path = Path(filename)
41
+ if not name_path.exists():
42
+ raise FileExistsError(f"{name_path} not exist.")
43
+ name = name_path.name
44
+ file_format = _find_unpack_format(filename)
45
+ file_postfix_list = _UNPACK_FORMATS[file_format][0]
46
+ for postfix in file_postfix_list:
47
+ if name.endswith(postfix):
48
+ target_name = name[:-len(postfix)]
49
+ break
50
+ else:
51
+ target_name = name.replace('.', '_')
52
+
53
+ if extract_dir is None:
54
+ extract_dir = f"./{target_name}/"
55
+ if not Path(extract_dir).exists():
56
+ os.mkdir(extract_dir)
57
+ shutil.unpack_archive(filename, extract_dir, format=format)
58
+ print(f"extract dir:\nfile://{Path(extract_dir).absolute()}")
59
+
60
+
61
+ if __name__ == "__main__":
62
+ # source_path = rel_to_abs('../web/', return_str=False, strict=True).name
63
+ # pack('../web/', format='bztar')
64
+ unpack('./web.tar.bz2')
65
+
66
+