Initial commit: 知识库管理器应用

- 实现基于 PySide6 的 GUI 界面
- 集成 FastAPI 知识库服务器 API
- 支持查看、编辑、提交 Markdown 文件
- 包含完整的 pytest-qt 测试套件
- 添加功能列表文档
This commit is contained in:
2026-01-30 12:03:12 +08:00
commit 0ab3d4f9c1
10 changed files with 695 additions and 0 deletions

203
main_window.py Normal file
View File

@@ -0,0 +1,203 @@
import sys
from PySide6.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QLineEdit, QPushButton, QListWidget, QTextEdit,
QMessageBox, QSplitter, QFileDialog
)
from PySide6.QtCore import Qt
from api_client import KnowledgeBaseAPI
class KnowledgeBaseApp(QMainWindow):
def __init__(self):
super().__init__()
self.api: Optional[KnowledgeBaseAPI] = None
self.current_filename: Optional[str] = None
self.init_ui()
def init_ui(self):
self.setWindowTitle('知识库管理器')
self.setGeometry(100, 100, 1200, 800)
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
# 服务器地址配置区域
server_layout = QHBoxLayout()
server_label = QLabel('服务器地址:')
self.server_input = QLineEdit('http://43.134.1.17:8800/')
self.server_input.setMinimumWidth(300)
self.config_button = QPushButton('配置')
self.config_button.clicked.connect(self.configure_server)
self.refresh_button = QPushButton('刷新列表')
self.refresh_button.clicked.connect(self.refresh_file_list)
server_layout.addWidget(server_label)
server_layout.addWidget(self.server_input)
server_layout.addWidget(self.config_button)
server_layout.addWidget(self.refresh_button)
server_layout.addStretch()
main_layout.addLayout(server_layout)
# 主内容区域(使用分割器)
splitter = QSplitter(Qt.Horizontal)
# 左侧:文件列表
left_widget = QWidget()
left_layout = QVBoxLayout(left_widget)
list_label = QLabel('文件列表 (.md):')
self.file_list = QListWidget()
self.file_list.itemClicked.connect(self.load_file)
left_layout.addWidget(list_label)
left_layout.addWidget(self.file_list)
# 右侧:编辑区域
right_widget = QWidget()
right_layout = QVBoxLayout(right_widget)
filename_layout = QHBoxLayout()
filename_label = QLabel('文件名:')
self.filename_input = QLineEdit()
self.filename_input.setPlaceholderText('输入文件名例如example.md')
filename_layout.addWidget(filename_label)
filename_layout.addWidget(self.filename_input)
self.text_editor = QTextEdit()
self.text_editor.setPlaceholderText('在此编辑 Markdown 内容...')
button_layout = QHBoxLayout()
self.save_button = QPushButton('保存到服务器')
self.save_button.clicked.connect(self.save_file)
self.post_button = QPushButton('提交新文件')
self.post_button.clicked.connect(self.post_new_file)
button_layout.addWidget(self.save_button)
button_layout.addWidget(self.post_button)
right_layout.addLayout(filename_layout)
right_layout.addWidget(self.text_editor)
right_layout.addLayout(button_layout)
splitter.addWidget(left_widget)
splitter.addWidget(right_widget)
splitter.setSizes([300, 900])
main_layout.addWidget(splitter)
# 状态栏
self.status_label = QLabel('就绪')
self.statusBar().addWidget(self.status_label)
def configure_server(self):
server_url = self.server_input.text().strip()
if not server_url:
QMessageBox.warning(self, '警告', '请输入服务器地址')
return
self.api = KnowledgeBaseAPI(server_url)
if self.api.test_connection():
self.status_label.setText(f'已连接到服务器: {server_url}')
QMessageBox.information(self, '成功', '服务器配置成功!')
self.refresh_file_list()
else:
QMessageBox.critical(self, '错误', '无法连接到服务器,请检查地址是否正确')
self.status_label.setText('连接失败')
def refresh_file_list(self):
if not self.api:
QMessageBox.warning(self, '警告', '请先配置服务器')
return
try:
files = self.api.get_file_list()
self.file_list.clear()
# 只显示 .md 文件
md_files = [f for f in files if f.endswith('.md')]
self.file_list.addItems(md_files)
self.status_label.setText(f'已加载 {len(md_files)} 个文件')
except Exception as e:
QMessageBox.critical(self, '错误', str(e))
self.status_label.setText('加载文件列表失败')
def load_file(self, item):
filename = item.text()
self.current_filename = filename
self.filename_input.setText(filename)
try:
content = self.api.get_file(filename)
self.text_editor.setPlainText(content)
self.status_label.setText(f'已加载文件: {filename}')
except Exception as e:
QMessageBox.critical(self, '错误', str(e))
self.status_label.setText('加载文件失败')
def save_file(self):
if not self.api:
QMessageBox.warning(self, '警告', '请先配置服务器')
return
if not self.current_filename:
QMessageBox.warning(self, '警告', '请先选择一个文件')
return
content = self.text_editor.toPlainText()
try:
self.api.post_file(self.current_filename, content)
QMessageBox.information(self, '成功', f'文件 {self.current_filename} 保存成功!')
self.status_label.setText(f'已保存文件: {self.current_filename}')
except Exception as e:
QMessageBox.critical(self, '错误', str(e))
self.status_label.setText('保存文件失败')
def post_new_file(self):
if not self.api:
QMessageBox.warning(self, '警告', '请先配置服务器')
return
filename = self.filename_input.text().strip()
if not filename:
QMessageBox.warning(self, '警告', '请输入文件名')
return
if not filename.endswith('.md'):
filename += '.md'
self.filename_input.setText(filename)
content = self.text_editor.toPlainText()
if not content:
QMessageBox.warning(self, '警告', '请输入文件内容')
return
try:
self.api.post_file(filename, content)
QMessageBox.information(self, '成功', f'文件 {filename} 提交成功!')
self.current_filename = filename
self.status_label.setText(f'已提交文件: {filename}')
self.refresh_file_list()
except Exception as e:
QMessageBox.critical(self, '错误', str(e))
self.status_label.setText('提交文件失败')
def main():
app = QApplication(sys.argv)
window = KnowledgeBaseApp()
window.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()