commit
885f5f701c
|
|
@ -6,8 +6,8 @@
|
|||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
<script type="module" crossorigin src="/baidu_netdisk/fe-static/assets/index-0e9928f4.js"></script>
|
||||
<link rel="stylesheet" href="/baidu_netdisk/fe-static/assets/index-b1903a85.css">
|
||||
<script type="module" crossorigin src="/baidu_netdisk/fe-static/assets/index-d1574f79.js"></script>
|
||||
<link rel="stylesheet" href="/baidu_netdisk/fe-static/assets/index-22f3f8f5.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="zanllp_dev_gradio_fe"></div>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,11 @@ from scripts.tool import get_windows_drives, convert_to_bytes
|
|||
import functools
|
||||
from scripts.logger import logger
|
||||
|
||||
|
||||
class AutoUpload:
|
||||
# 已成等待发送图像的队列
|
||||
files = []
|
||||
task_id: Union[None, str] = None
|
||||
|
||||
def exec_ops(args: Union[List[str], str]):
|
||||
args = [args] if isinstance(args, str) else args
|
||||
res = ""
|
||||
|
|
@ -331,4 +335,27 @@ def baidu_netdisk_api(_: Any, app: FastAPI):
|
|||
async def image_geninfo(path: str):
|
||||
from modules import extras
|
||||
geninfo,_ = extras.images.read_info_from_image(Image.open(path))
|
||||
return geninfo
|
||||
return geninfo
|
||||
|
||||
class AutoUploadParams(BaseModel):
|
||||
recv_dir: str
|
||||
@app.post(pre+"/auto_upload")
|
||||
async def auto_upload(req: AutoUploadParams):
|
||||
tick_info = None
|
||||
if AutoUpload.task_id:
|
||||
task = BaiduyunTask.get_by_id(AutoUpload.task_id)
|
||||
tick_info = await task.get_tick()
|
||||
if not task.running:
|
||||
AutoUpload.task_id = None
|
||||
else:
|
||||
recived_file = AutoUpload.files
|
||||
AutoUpload.files = []
|
||||
if len(recived_file):
|
||||
logger.info(f"创建上传任务 {recived_file} ----> {req.recv_dir}")
|
||||
task = await BaiduyunTask.create('upload', recived_file, req.recv_dir)
|
||||
AutoUpload.task_id = task.id
|
||||
return {
|
||||
"tick_info": tick_info,
|
||||
"pending_files": AutoUpload.files
|
||||
}
|
||||
|
||||
|
|
@ -31,17 +31,20 @@ def get_matched_summary():
|
|||
file_name = "BaiduPCS-Go-v3.9.0-windows-x86"
|
||||
if not file_name:
|
||||
raise Exception(f"找不到对应的文件,请携带此信息找开发者 machine:{machine} system:{system}")
|
||||
return file_name, f"https://github.com/qjfoidnh/BaiduPCS-Go/releases/download/v3.9.0/{file_name}.zip"
|
||||
return file_name, f"https://github.com/qjfoidnh/BaiduPCS-Go/releases/download/v3.9.0/{file_name}.zip", f"http://static.zanllp.cn/{file_name}.zip"
|
||||
|
||||
|
||||
def download_bin_file():
|
||||
summary, url = get_matched_summary()
|
||||
summary, url, fallback_url = get_matched_summary()
|
||||
|
||||
# 下载文件保存路径
|
||||
download_path = "BaiduPCS-Go.zip"
|
||||
|
||||
try:
|
||||
# 下载文件并保存
|
||||
urllib.request.urlretrieve(url, download_path)
|
||||
urllib.request.urlretrieve(url, download_path)
|
||||
except:
|
||||
urllib.request.urlretrieve(fallback_url, download_path)
|
||||
|
||||
# 解压缩
|
||||
with zipfile.ZipFile(download_path, "r") as zip_ref:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from scripts.api import baidu_netdisk_api, send_img_path
|
||||
from fastapi import FastAPI
|
||||
from scripts.api import baidu_netdisk_api, send_img_path, AutoUpload
|
||||
from modules import script_callbacks, generation_parameters_copypaste as send, extras
|
||||
from scripts.bin import (
|
||||
bin_file_name,
|
||||
|
|
@ -6,8 +7,9 @@ from scripts.bin import (
|
|||
check_bin_exists,
|
||||
download_bin_file,
|
||||
)
|
||||
from scripts.tool import cwd
|
||||
from scripts.tool import cwd, debounce
|
||||
from PIL import Image
|
||||
from scripts.logger import logger
|
||||
|
||||
|
||||
"""
|
||||
|
|
@ -15,7 +17,7 @@ api函数声明和启动分离方便另外一边被外部调用
|
|||
"""
|
||||
|
||||
not_exists_msg = (
|
||||
f"找不到{bin_file_name},尝试手动从 {get_matched_summary()[1]} 下载,下载后放到 {cwd} 文件夹下,重启界面"
|
||||
f"找不到{bin_file_name},尝试手动从 {get_matched_summary()[1]} 或者 {get_matched_summary()[2]} 下载,下载后放到 {cwd} 文件夹下,重启界面"
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -70,5 +72,13 @@ def on_ui_tabs():
|
|||
return ((baidu_netdisk, "百度云", "baiduyun"),)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def on_img_saved(params: script_callbacks.ImageSaveParams):
|
||||
AutoUpload.files.append(params.filename)
|
||||
|
||||
|
||||
script_callbacks.on_ui_tabs(on_ui_tabs)
|
||||
script_callbacks.on_app_started(baidu_netdisk_api)
|
||||
script_callbacks.on_image_saved(on_img_saved)
|
||||
|
|
@ -46,6 +46,29 @@ def convert_to_bytes(file_size_str):
|
|||
return int(size)
|
||||
else:
|
||||
raise ValueError(f"Invalid file size string '{file_size_str}'")
|
||||
|
||||
|
||||
import asyncio
|
||||
|
||||
|
||||
def debounce(delay):
|
||||
"""用于优化高频事件的装饰器"""
|
||||
|
||||
def decorator(func):
|
||||
from typing import Union
|
||||
task: Union[None, asyncio.Task] = None
|
||||
|
||||
async def debounced(*args, **kwargs):
|
||||
nonlocal task
|
||||
if task:
|
||||
task.cancel()
|
||||
task = asyncio.create_task(asyncio.sleep(delay))
|
||||
await task
|
||||
return await func(*args, **kwargs)
|
||||
|
||||
return debounced
|
||||
|
||||
return decorator
|
||||
|
||||
is_dev = "APP_ENV" in os.environ and os.environ["APP_ENV"] == "dev"
|
||||
cwd = os.path.normpath(os.path.join(__file__, "../../"))
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ declare module '@vue/runtime-core' {
|
|||
ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
|
||||
ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
|
||||
AButton: typeof import('ant-design-vue/es')['Button']
|
||||
ACol: typeof import('ant-design-vue/es')['Col']
|
||||
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
|
||||
AForm: typeof import('ant-design-vue/es')['Form']
|
||||
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||
|
|
@ -23,8 +24,10 @@ declare module '@vue/runtime-core' {
|
|||
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
|
||||
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||
AProgress: typeof import('ant-design-vue/es')['Progress']
|
||||
ARow: typeof import('ant-design-vue/es')['Row']
|
||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
|
||||
AStatistic: typeof import('ant-design-vue/es')['Statistic']
|
||||
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
||||
ATabPane: typeof import('ant-design-vue/es')['TabPane']
|
||||
ATabs: typeof import('ant-design-vue/es')['Tabs']
|
||||
|
|
|
|||
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
|
|
@ -5,8 +5,8 @@
|
|||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
<script type="module" crossorigin src="/baidu_netdisk/fe-static/assets/index-0e9928f4.js"></script>
|
||||
<link rel="stylesheet" href="/baidu_netdisk/fe-static/assets/index-b1903a85.css">
|
||||
<script type="module" crossorigin src="/baidu_netdisk/fe-static/assets/index-d1574f79.js"></script>
|
||||
<link rel="stylesheet" href="/baidu_netdisk/fe-static/assets/index-22f3f8f5.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="zanllp_dev_gradio_fe"></div>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { getAutoCompletedTagList } from './taskRecord/autoComplete'
|
|||
import { useTaskListStore } from './store/useTaskListStore'
|
||||
import TaskOperation from './taskRecord/taskOperation.vue'
|
||||
import { useIntervalFn } from '@vueuse/core'
|
||||
import autoUpload from './autoUpload/autoUpload.vue'
|
||||
|
||||
const user = ref<UserInfo>()
|
||||
const bduss = ref('')
|
||||
|
|
@ -108,6 +109,9 @@ useIntervalFn(() => {
|
|||
</template>
|
||||
<task-operation />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="3" tab="自动上传">
|
||||
<auto-upload/>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-skeleton>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -168,3 +168,14 @@ export const genInfoCompleted = async () => {
|
|||
export const getImageGenerationInfo = async (path: string) => {
|
||||
return (await axiosInst.get(`/image_geninfo?path=${encodeURIComponent(path)}`)).data as string
|
||||
}
|
||||
|
||||
export const autoUploadOutput = async (recv_dir: string) => {
|
||||
const resp = await axiosInst.post(`/auto_upload`, { recv_dir })
|
||||
return resp.data as {
|
||||
pending_files: string[]
|
||||
tick_info?: {
|
||||
tasks: UploadTaskTickStatus[],
|
||||
task_summary: UploadTaskSummary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, watchEffect } from 'vue'
|
||||
import { autoUploadOutput, type UploadTaskSummary } from '@/api/index'
|
||||
import { delay, Task } from 'vue3-ts-util'
|
||||
import { useGlobalStore } from '@/store/useGlobalStore'
|
||||
|
||||
const emit = defineEmits<{ (e: 'runningChange', v: boolean): void }>()
|
||||
const global = useGlobalStore()
|
||||
const pendingFiles = ref<string[]>([])
|
||||
const task = ref<ReturnType<typeof runPollTask>>()
|
||||
const running = computed(() => !!(task.value || pendingFiles.value.length))
|
||||
watchEffect(() => emit('runningChange', running.value))
|
||||
const taskLog = reactive(new Map<string, UploadTaskSummary>())
|
||||
const taskLogList = computed(() => Array.from(taskLog.values()))
|
||||
const completedFiles = computed(() => taskLogList.value.reduce((p, c) => p + c.n_success_files, 0))
|
||||
const failededFiles = computed(() => taskLogList.value.reduce((p, c) => p + c.n_failed_files, 0))
|
||||
// const allFiles = computed(() => taskLogList.value.reduce((p, c) => p + c.n_files, 0) + pendingFiles.value.length)
|
||||
|
||||
const runPollTask = () => {
|
||||
return Task.run({
|
||||
action: async () => {
|
||||
const res = await autoUploadOutput(global.autoUploadRecvDir)
|
||||
if (res.tick_info) {
|
||||
taskLog.set(res.tick_info.task_summary.id, res.tick_info.task_summary)
|
||||
}
|
||||
pendingFiles.value = res.pending_files
|
||||
await delay(10000 * Math.random())
|
||||
return res
|
||||
},
|
||||
pollInterval: 30_000
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const onStart = async () => {
|
||||
if (task.value) {
|
||||
task.value.clearTask()
|
||||
task.value = undefined
|
||||
pendingFiles.value = []
|
||||
} else {
|
||||
task.value = runPollTask()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="container">
|
||||
<AInput v-model:value="global.autoUploadRecvDir"></AInput>
|
||||
<AButton @click="onStart" :loading="running">{{ task ? '暂停' : '开始' }}</AButton>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-statistic title="等待上传数量" :value="pendingFiles.length" style="margin-right: 50px" />
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-statistic title="上传失败数量" :value="failededFiles" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-statistic title="已完成数量" :value="completedFiles" style="margin-right: 50px" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
margin: 16px;
|
||||
|
||||
&>* {
|
||||
margin: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -495,7 +495,7 @@ function useFileItemActions () {
|
|||
v-if="props.target === 'local' && viewMode !== 'line' && isImageFile(file.name)"
|
||||
:src="global.enableThumbnail ? toImageThumbnailUrl(file, viewMode === 'grid' ? void 0 : '512,512') : toRawFileUrl(file)"
|
||||
:fallback="fallbackImage"
|
||||
:preview="{ src: toRawFileUrl(sortedFiles[previewIdx]), onVisibleChange: onPreviewVisibleChange }">
|
||||
:preview="{ src: sortedFiles[previewIdx] ? toRawFileUrl(sortedFiles[previewIdx]) : '', onVisibleChange: onPreviewVisibleChange }">
|
||||
</a-image>
|
||||
<template v-else>
|
||||
<file-outlined class="icon" v-if="file.type === 'file'" />
|
||||
|
|
|
|||
|
|
@ -9,15 +9,17 @@ export const useGlobalStore = defineStore('useGlobalStore', () => {
|
|||
const autoCompletedDirList = ref([] as ReturnType<typeof getAutoCompletedTagList>)
|
||||
const enableThumbnail = ref(true)
|
||||
const stackViewSplit = ref(50)
|
||||
const autoUploadRecvDir = ref('/')
|
||||
return {
|
||||
conf,
|
||||
autoCompletedDirList,
|
||||
enableThumbnail,
|
||||
stackViewSplit,
|
||||
autoUploadRecvDir,
|
||||
...typedEventEmitter<{ createNewTask: Partial<UploadTaskSummary> }>()
|
||||
}
|
||||
}, {
|
||||
persist: {
|
||||
paths: ['enableThumbnail', 'stackViewSplit']
|
||||
paths: ['enableThumbnail', 'stackViewSplit', 'autoUploadRecvDir']
|
||||
}
|
||||
})
|
||||
Loading…
Reference in New Issue