feat(interface): 改进状态显示

This commit is contained in:
2026-01-13 23:39:10 +08:00
parent 016ae16100
commit 473a3bba8f
9 changed files with 615 additions and 49 deletions

View File

@@ -7,6 +7,11 @@ from textual.widgets import Button, Footer, Header, Label, Markdown, Static
import heurams.services.version as version
from heurams.context import *
import platform
import shutil
import psutil
import os
import sys
class AboutScreen(Screen):
@@ -18,6 +23,15 @@ class AboutScreen(Screen):
yield Header(show_clock=True)
with ScrollableContainer(id="about_container"):
yield Label("[b]关于与版本信息[/b]")
# 获取系统信息
textual_version = self._get_textual_version()
terminal_info = self._get_terminal_info()
python_version = self._get_python_version()
os_version = self._get_os_version()
disk_usage = self._get_disk_usage()
memory_info = self._get_memory_info()
about_text = f"""
# 关于 "潜进"
@@ -33,6 +47,10 @@ class AboutScreen(Screen):
如果您觉得这个软件有用, 请给它添加一个星标 :)
我们的共同目标是为人人带来高品质的辅助记忆 & 学习软件.
不管您来自何方, 我们都欢迎您加入社区并做出贡献.
开发人员:
- Wang Zhiyu([@pluvium27](https://github.com/pluvium27)): 项目作者
@@ -43,40 +61,22 @@ class AboutScreen(Screen):
- [Kazuaki Tanida](https://github.com/slaypni): SM-15 算法的 CoffeeScript 实现
- [Thoughts Memo](https://www.zhihu.com/people/L.M.Sherlock): 文献参考
# 参与贡献
我们是一个年轻且包容的社区, 由技术人员, 设计师, 文书工作者, 以及创意人员共同构成,
# 运行环境信息
通过我们协力开发的软件为所有人谋取福祉.
Textual 框架版本: {textual_version}
终端模拟器: {terminal_info}
Python 解释器版本: {python_version}
操作系统版本: {os_version}
存储余量: {disk_usage}
内存大小: {memory_info}
上述工作不可避免地让我们确立了下列价值观 (取自 KDE 宣言):
- 开放治理 确保更多人能参与我们的领导和决策进程;
- 自由软件 确保我们的工作成果随时能为所有人所用;
- 多样包容 确保所有人都能加入社区并参加工作;
- 创新精神 确保新思路能不断涌现并服务于所有人;
- 共同产权 确保我们能团结一致;
- 迎合用户 确保我们的成果对所有人有用.
综上所述, 在为我们共同目标奋斗的过程中, 我们认为上述价值观反映了我们社区的本质, 是我们始终如一地保持初心的关键所在.
这是一项立足于协作精神的事业, 它的运作和产出不受任何单一个人或者机构的操纵.
我们的共同目标是为人人带来高品质的辅助记忆 & 学习软件.
不管您来自何方, 我们都欢迎您加入社区并做出贡献.
"""
# """
# 学术数据
# "潜进" 的用户数据可用于科学方面的研究, 我们将在未来版本添加学术数据的收集和展示平台
# """
yield Markdown(about_text, classes="about-markdown")
yield Button(
@@ -94,3 +94,68 @@ class AboutScreen(Screen):
event.stop()
if event.button.id == "back_button":
self.action_go_back()
def _get_textual_version(self) -> str:
"""获取 Textual 框架版本"""
try:
import textual
return textual.__version__
except (ImportError, AttributeError):
return "未知"
def _get_terminal_info(self) -> str:
"""获取终端模拟器信息"""
terminal = shutil.which("terminal")
if terminal:
return terminal
# 尝试从环境变量获取
terminal_env = os.environ.get('TERM_PROGRAM') or os.environ.get('TERM')
return terminal_env or "未知"
def _get_python_version(self) -> str:
"""获取 Python 解释器版本"""
return platform.python_version()
def _get_os_version(self) -> str:
"""获取操作系统版本"""
try:
if platform.system() == "Darwin":
# macOS
import subprocess
result = subprocess.run(['sw_vers', '-productVersion'],
capture_output=True, text=True)
return f"macOS {result.stdout.strip()}"
elif platform.system() == "Windows":
# Windows
return f"Windows {platform.release()}"
elif platform.system() == "Linux":
# Linux - 尝试获取发行版信息
try:
import distro
return f"{distro.name()} {distro.version()}"
except (ImportError, AttributeError):
return platform.platform()
else:
return platform.platform()
except Exception:
return platform.platform()
def _get_disk_usage(self) -> str:
"""获取磁盘使用情况"""
try:
usage = psutil.disk_usage('/')
free_gb = usage.free / (1024 ** 3)
total_gb = usage.total / (1024 ** 3)
percent_free = (free_gb / total_gb) * 100
return f"{free_gb:.1f} GB ({percent_free:.1f}%)"
except Exception:
return "未知"
def _get_memory_info(self) -> str:
"""获取内存信息"""
try:
memory = psutil.virtual_memory()
total_gb = memory.total / (1024 ** 3)
return f"{total_gb:.1f} GB"
except Exception:
return "未知"

View File

@@ -1,6 +1,3 @@
"""LLM 聊天界面"""
import asyncio
from pathlib import Path
from typing import Optional
@@ -19,7 +16,7 @@ logger = get_logger(__name__)
class LLMChatScreen(Screen):
"""LLM 聊天屏幕"""
SUB_TITLE = "AI 聊天"
SUB_TITLE = "语言模型集成"
BINDINGS = [
("q", "go_back", "返回"),
("ctrl+s", "save_session", "保存会话"),

View File

@@ -5,7 +5,7 @@ from textual.containers import ScrollableContainer
from textual.reactive import reactive
from textual.screen import Screen
from textual.widget import Widget
from textual.widgets import Button, Footer, Header, Label, Markdown, Static
from textual.widgets import Button, Footer, Header, Label, Markdown, Static, Rule, Sparkline
import heurams.kernel.particles as pt
import heurams.services.hasher as hasher
@@ -34,6 +34,7 @@ class PreparationScreen(Screen):
super().__init__(name=None, id=None, classes=None)
self.repo = repo
self.repostat = repostat
self.load_data()
def compose(self) -> ComposeResult:
yield Header(show_clock=True)
@@ -43,7 +44,7 @@ class PreparationScreen(Screen):
f"仓库路径: {config_var.get()['paths']['data']}/repo/[b]{self.repostat['dirname']}[/b]"
)
yield Label(f"\n单元数量: {len(self.repo)}\n")
yield Label(f"单次记忆数量: {self.scheduled_num}", id="schnum_label")
yield Label(f"最小记忆分组: {self.scheduled_num}\n", id="schnum_label")
yield Button(
"开始记忆",
@@ -58,11 +59,15 @@ class PreparationScreen(Screen):
classes="precache-button",
)
yield Static(f"\n单元预览:\n")
for i in self._get_full_content().replace("/", "").splitlines():
yield Static()
yield Sparkline(self.spark_line_arr, summary_function=max)
yield Rule()
#yield Static(str(self.spark_line_arr))
yield Static(f"单元状态预览:\n")
for i in self.content.splitlines():
yield Static(i, classes="full")
yield Footer()
# def watch_scheduled_num(self, old_scheduled_num, new_scheduled_num):
# logger.debug("响应", old_scheduled_num, "->", new_scheduled_num)
# try:
@@ -71,14 +76,27 @@ class PreparationScreen(Screen):
# except:
# pass
def _get_full_content(self):
def load_data(self):
content = ""
spark_line_arr = []
for i in self.repo.ident_index:
n = pt.Nucleon.create_on_nucleonic_data(
nucleonic_data=self.repo.nucleonic_data_lict.get_itemic_unit(i)
)
content += f"{n['content']} \n"
return content
e = pt.Electron.create_on_electonic_data(electronic_data=self.repo.electronic_data_lict.get_itemic_unit(i))
statstr = ""
if e.is_activated():
statstr = '[#00ff00]A[/]'
if e.is_due():
statstr = '[#ffff00]R[/]'
#statstr += ('[dim]' + str(e.rept(real_rept=True)).zfill(2)+'[/]')
else:
statstr = '[#ff0000]U[/]'
spark_line_arr.append(e.rept(real_rept=True))
content += f" {statstr} {n['content'].replace('/', '')} \n"
self.content = content
self.spark_line_arr = spark_line_arr
def action_go_back(self):
self.app.pop_screen()