Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Auto-sync from GitHub Actions
Browse files- core/counter.py +23 -2
- ui_nicegui.py +115 -18
core/counter.py
CHANGED
|
@@ -355,12 +355,33 @@ async def add_keywords(words: list[str]):
|
|
| 355 |
_dirty_keywords[word] += 1
|
| 356 |
_check_sync()
|
| 357 |
|
| 358 |
-
async def add_bad_case(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 359 |
global _dirty_bad_cases, _memory_bad_cases
|
| 360 |
entry = {
|
|
|
|
| 361 |
'q': query,
|
| 362 |
't': datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ'),
|
| 363 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 364 |
if platform:
|
| 365 |
entry['platform'] = platform
|
| 366 |
if settings:
|
|
@@ -390,4 +411,4 @@ def get_history() -> list[dict]:
|
|
| 390 |
return list(_memory_history)
|
| 391 |
|
| 392 |
async def force_sync():
|
| 393 |
-
await _perform_sync()
|
|
|
|
| 355 |
_dirty_keywords[word] += 1
|
| 356 |
_check_sync()
|
| 357 |
|
| 358 |
+
async def add_bad_case(
|
| 359 |
+
query: str,
|
| 360 |
+
platform: str = '',
|
| 361 |
+
settings: dict | None = None,
|
| 362 |
+
feedback_type: str = 'search_bad_case',
|
| 363 |
+
detail: str = '',
|
| 364 |
+
tag: str = '',
|
| 365 |
+
current_cn_name: str = '',
|
| 366 |
+
suggested_cn_name: str = '',
|
| 367 |
+
category: str = '',
|
| 368 |
+
) -> None:
|
| 369 |
global _dirty_bad_cases, _memory_bad_cases
|
| 370 |
entry = {
|
| 371 |
+
'type': feedback_type,
|
| 372 |
'q': query,
|
| 373 |
't': datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ'),
|
| 374 |
}
|
| 375 |
+
optional_fields = {
|
| 376 |
+
'detail': detail,
|
| 377 |
+
'tag': tag,
|
| 378 |
+
'current_cn_name': current_cn_name,
|
| 379 |
+
'suggested_cn_name': suggested_cn_name,
|
| 380 |
+
'category': category,
|
| 381 |
+
}
|
| 382 |
+
for key, value in optional_fields.items():
|
| 383 |
+
if value:
|
| 384 |
+
entry[key] = value
|
| 385 |
if platform:
|
| 386 |
entry['platform'] = platform
|
| 387 |
if settings:
|
|
|
|
| 411 |
return list(_memory_history)
|
| 412 |
|
| 413 |
async def force_sync():
|
| 414 |
+
await _perform_sync()
|
ui_nicegui.py
CHANGED
|
@@ -1016,6 +1016,7 @@ class DanbooruSearchUI:
|
|
| 1016 |
).classes('w-full')
|
| 1017 |
self.result_table.on('selection', self._update_selection_display)
|
| 1018 |
self.result_table.on('link_click', self._mark_interaction)
|
|
|
|
| 1019 |
self.result_table.on('pagination', lambda _: self._save_config())
|
| 1020 |
|
| 1021 |
# 自定义行模板:行背景色按分类,整行悬浮显示 wiki(NSFW模糊行除外)
|
|
@@ -1036,8 +1037,16 @@ class DanbooruSearchUI:
|
|
| 1036 |
<template v-if="col.name === 'tag' || col.name === 'cn_name'">
|
| 1037 |
<div :class="props.row._nsfw_blocked ? 'nsfw-blur-cell' : ''">
|
| 1038 |
<template v-if="col.name === 'cn_name' && col.value">
|
| 1039 |
-
<span style="font-size:14px">
|
| 1040 |
-
{{ col.value.split(',')[0] }}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1041 |
</span>
|
| 1042 |
</template>
|
| 1043 |
<template v-else-if="col.name === 'tag'">
|
|
@@ -1908,27 +1917,115 @@ class DanbooruSearchUI:
|
|
| 1908 |
else:
|
| 1909 |
ui.notify('暂无标签可复制', type='warning')
|
| 1910 |
|
| 1911 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1912 |
from platform_utils import PLATFORM
|
| 1913 |
query = self.current_query_str.strip()
|
| 1914 |
if len(query) <= 1:
|
| 1915 |
ui.notify('搜索词太短,无法提交反馈。', type='warning', timeout=2000)
|
| 1916 |
return
|
| 1917 |
-
|
| 1918 |
-
|
| 1919 |
-
|
| 1920 |
-
|
| 1921 |
-
|
| 1922 |
-
'
|
| 1923 |
-
'
|
| 1924 |
-
|
| 1925 |
-
|
| 1926 |
-
|
| 1927 |
-
|
| 1928 |
-
|
| 1929 |
-
|
| 1930 |
-
|
| 1931 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1932 |
|
| 1933 |
# ── 页面路由 ───────────────────────────────────────────────────────────────────
|
| 1934 |
|
|
|
|
| 1016 |
).classes('w-full')
|
| 1017 |
self.result_table.on('selection', self._update_selection_display)
|
| 1018 |
self.result_table.on('link_click', self._mark_interaction)
|
| 1019 |
+
self.result_table.on('translation_feedback', self.report_translation_error)
|
| 1020 |
self.result_table.on('pagination', lambda _: self._save_config())
|
| 1021 |
|
| 1022 |
# 自定义行模板:行背景色按分类,整行悬浮显示 wiki(NSFW模糊行除外)
|
|
|
|
| 1037 |
<template v-if="col.name === 'tag' || col.name === 'cn_name'">
|
| 1038 |
<div :class="props.row._nsfw_blocked ? 'nsfw-blur-cell' : ''">
|
| 1039 |
<template v-if="col.name === 'cn_name' && col.value">
|
| 1040 |
+
<span style="font-size:14px;display:inline-flex;align-items:center;gap:4px;">
|
| 1041 |
+
<span>{{ col.value.split(',')[0] }}</span>
|
| 1042 |
+
<q-btn icon="report_problem"
|
| 1043 |
+
size="sm"
|
| 1044 |
+
dense flat round
|
| 1045 |
+
color="grey-5"
|
| 1046 |
+
padding="xs"
|
| 1047 |
+
@click.stop.prevent="console.debug('[DanbooruSearch] translation_feedback click', props.row); $parent.$emit('translation_feedback', props.row)">
|
| 1048 |
+
<q-tooltip>反馈翻译错误</q-tooltip>
|
| 1049 |
+
</q-btn>
|
| 1050 |
</span>
|
| 1051 |
</template>
|
| 1052 |
<template v-else-if="col.name === 'tag'">
|
|
|
|
| 1917 |
else:
|
| 1918 |
ui.notify('暂无标签可复制', type='warning')
|
| 1919 |
|
| 1920 |
+
def _feedback_settings(self) -> dict:
|
| 1921 |
+
return {
|
| 1922 |
+
'top_k': int(self.input_top_k.value) if self.input_top_k else None,
|
| 1923 |
+
'segmentation': self.input_segment.value if self.input_segment else None,
|
| 1924 |
+
'nsfw': self.input_nsfw.value if self.input_nsfw else None,
|
| 1925 |
+
}
|
| 1926 |
+
|
| 1927 |
+
def report_bad_case(self):
|
| 1928 |
from platform_utils import PLATFORM
|
| 1929 |
query = self.current_query_str.strip()
|
| 1930 |
if len(query) <= 1:
|
| 1931 |
ui.notify('搜索词太短,无法提交反馈。', type='warning', timeout=2000)
|
| 1932 |
return
|
| 1933 |
+
|
| 1934 |
+
with ui.dialog() as dialog, ui.card().classes('w-full max-w-lg'):
|
| 1935 |
+
ui.label('反馈搜索问题').classes('text-base font-bold text-gray-800')
|
| 1936 |
+
ui.label(f'当前搜索词:{query}').classes('text-sm text-gray-600')
|
| 1937 |
+
detail_input = ui.textarea(
|
| 1938 |
+
label='具体问题(可选)',
|
| 1939 |
+
placeholder='例如:结果偏题、缺少某个关键标签、召回了不相关角色/作品...',
|
| 1940 |
+
).props('outlined autogrow maxlength=500 counter').classes('w-full')
|
| 1941 |
+
|
| 1942 |
+
async def submit_feedback():
|
| 1943 |
+
detail = (detail_input.value or '').strip()
|
| 1944 |
+
|
| 1945 |
+
submit_btn.disable()
|
| 1946 |
+
try:
|
| 1947 |
+
await counter.add_bad_case(
|
| 1948 |
+
query,
|
| 1949 |
+
platform=PLATFORM,
|
| 1950 |
+
settings=self._feedback_settings(),
|
| 1951 |
+
feedback_type='search_bad_case',
|
| 1952 |
+
detail=detail,
|
| 1953 |
+
)
|
| 1954 |
+
if self.bad_case_btn is not None:
|
| 1955 |
+
self.bad_case_btn.disable()
|
| 1956 |
+
dialog.close()
|
| 1957 |
+
ui.notify('感谢反馈!我们会持续优化。', type='positive', timeout=3000)
|
| 1958 |
+
except Exception as e:
|
| 1959 |
+
print(f'[UI] bad_case 记录异常: {e}')
|
| 1960 |
+
submit_btn.enable()
|
| 1961 |
+
ui.notify('记录失败,请稍后再试。', type='warning', timeout=3000)
|
| 1962 |
+
|
| 1963 |
+
with ui.row().classes('w-full justify-end gap-2'):
|
| 1964 |
+
ui.button('取消', on_click=dialog.close).props('flat color=grey-7')
|
| 1965 |
+
submit_btn = ui.button('提交反馈', on_click=submit_feedback).props('unelevated color=primary')
|
| 1966 |
+
dialog.open()
|
| 1967 |
+
|
| 1968 |
+
def report_translation_error(self, e):
|
| 1969 |
+
from platform_utils import PLATFORM
|
| 1970 |
+
raw_args = getattr(e, 'args', None)
|
| 1971 |
+
# print(f'[UI] translation_feedback event received: {raw_args!r}', flush=True)
|
| 1972 |
+
row = raw_args
|
| 1973 |
+
if isinstance(row, list) and row:
|
| 1974 |
+
row = row[0]
|
| 1975 |
+
if not isinstance(row, dict):
|
| 1976 |
+
print(f'[UI] translation_feedback invalid payload: {raw_args!r}', flush=True)
|
| 1977 |
+
ui.notify('无法读取当前词条信息。', type='warning', timeout=2000)
|
| 1978 |
+
return
|
| 1979 |
+
|
| 1980 |
+
tag = str(row.get('tag') or '').strip()
|
| 1981 |
+
current_cn_name = str(row.get('cn_name') or '').strip()
|
| 1982 |
+
if not tag:
|
| 1983 |
+
ui.notify('无法读取当前词条。', type='warning', timeout=2000)
|
| 1984 |
+
return
|
| 1985 |
+
|
| 1986 |
+
query = self.current_query_str.strip()
|
| 1987 |
+
current_cn_first = current_cn_name.split(',', 1)[0].strip()
|
| 1988 |
+
with ui.dialog() as dialog, ui.card().classes('w-full max-w-lg'):
|
| 1989 |
+
ui.label('反馈翻译错误').classes('text-base font-bold text-gray-800')
|
| 1990 |
+
ui.label(f'词条:{tag}').classes('text-sm font-mono text-gray-700')
|
| 1991 |
+
ui.label(f'当前中文名:{current_cn_first or current_cn_name or "(空)"}').classes('text-sm text-gray-600')
|
| 1992 |
+
suggested_input = ui.input(
|
| 1993 |
+
label='建议中文名(可选)',
|
| 1994 |
+
placeholder='如果有更合适的译名,可以填在这里',
|
| 1995 |
+
).props('outlined maxlength=120 counter').classes('w-full')
|
| 1996 |
+
detail_input = ui.textarea(
|
| 1997 |
+
label='问题说明(可选)',
|
| 1998 |
+
placeholder='例如:含义不准确、作品/角色名误译、中文名缺失...',
|
| 1999 |
+
).props('outlined autogrow maxlength=500 counter').classes('w-full')
|
| 2000 |
+
|
| 2001 |
+
async def submit_feedback():
|
| 2002 |
+
suggested = (suggested_input.value or '').strip()
|
| 2003 |
+
detail = (detail_input.value or '').strip()
|
| 2004 |
+
|
| 2005 |
+
submit_btn.disable()
|
| 2006 |
+
try:
|
| 2007 |
+
await counter.add_bad_case(
|
| 2008 |
+
query,
|
| 2009 |
+
platform=PLATFORM,
|
| 2010 |
+
settings=self._feedback_settings(),
|
| 2011 |
+
feedback_type='translation_error',
|
| 2012 |
+
detail=detail,
|
| 2013 |
+
tag=tag,
|
| 2014 |
+
current_cn_name=current_cn_name,
|
| 2015 |
+
suggested_cn_name=suggested,
|
| 2016 |
+
category=str(row.get('category') or ''),
|
| 2017 |
+
)
|
| 2018 |
+
dialog.close()
|
| 2019 |
+
ui.notify('感谢反馈!这条翻译问题已记录。', type='positive', timeout=3000)
|
| 2020 |
+
except Exception as e:
|
| 2021 |
+
print(f'[UI] translation_error 记录异常: {e}')
|
| 2022 |
+
submit_btn.enable()
|
| 2023 |
+
ui.notify('记录失败,请稍后再试。', type='warning', timeout=3000)
|
| 2024 |
+
|
| 2025 |
+
with ui.row().classes('w-full justify-end gap-2'):
|
| 2026 |
+
ui.button('取消', on_click=dialog.close).props('flat color=grey-7')
|
| 2027 |
+
submit_btn = ui.button('提交反馈', on_click=submit_feedback).props('unelevated color=primary')
|
| 2028 |
+
dialog.open()
|
| 2029 |
|
| 2030 |
# ── 页面路由 ───────────────────────────────────────────────────────────────────
|
| 2031 |
|