SAkizuki commited on
Commit
92f8acf
·
verified ·
1 Parent(s): 57c49db

Auto-sync from GitHub Actions

Browse files
Files changed (2) hide show
  1. core/counter.py +23 -2
  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(query: str, platform: str = '', settings: dict | None = None) -> None:
 
 
 
 
 
 
 
 
 
 
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
- async def report_bad_case(self):
 
 
 
 
 
 
 
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
- if self.bad_case_btn is not None:
1918
- self.bad_case_btn.disable()
1919
- try:
1920
- settings = {
1921
- 'top_k': int(self.input_top_k.value) if self.input_top_k else None,
1922
- 'segmentation': self.input_segment.value if self.input_segment else None,
1923
- 'nsfw': self.input_nsfw.value if self.input_nsfw else None,
1924
- }
1925
- await counter.add_bad_case(query, platform=PLATFORM, settings=settings)
1926
- ui.notify('感谢反馈!我们会持续优化。', type='positive', timeout=3000)
1927
- except Exception as e:
1928
- print(f'[UI] bad_case 记录异常: {e}')
1929
- ui.notify('记录失败,请稍后再试。', type='warning', timeout=3000)
1930
- if self.bad_case_btn is not None:
1931
- self.bad_case_btn.enable()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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