feat(chat): màn giới thiệu khi hội thoại còn rỗng
Bấm "Cuộc trò chuyện mới" trước đây để lại một khung trắng: không có gì nói người dùng đang làm trong project nào, thư mục có bao nhiêu tệp, hay bắt đầu từ đâu. Đây là trạng thái RỖNG — một trong bốn trạng thái mà mọi khung dữ liệu phải có, và là trạng thái duy nhất người dùng nhìn thấy trước khi gõ chữ đầu tiên. Gồm lời chào theo tên, dòng bối cảnh (project · số tệp · số skill đang bật), và bốn thẻ gợi ý. Hai quyết định: - Thẻ ĐIỀN câu gợi ý vào ô nhập chứ không gửi luôn. Câu gợi ý là điểm bắt đầu; người dùng gần như luôn cần thêm chi tiết của riêng họ, và gửi ngay sẽ tiêu một lượt gọi model cho một câu hỏi chung chung. - Dấu phía trên lời chào không bấm được — nó là dấu hiệu thị giác. Một nút không làm gì tệ hơn không có nút. Dòng bối cảnh phân biệt KHÔNG BIẾT với 0: đếm được 0 tệp thì hiện "0 tệp", còn không đọc được thư mục thì bỏ hẳn mảnh đó — hiện "0 tệp" khi người dùng vừa thấy có tệp trong thư mục còn tệ hơn là thiếu một mảnh. show_welcome() được móc ở ba chỗ: new_session(), load_conversation() (theo số tin nhắn đã lưu), và TRƯỚC mọi nhánh add_user trong turn runner — đặt sau từng add_user() thì dễ sót đúng một nhánh, và nhánh đó sẽ hiện cả hai thứ cùng lúc. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@ from ...state import AppContext
|
||||
from ...theme import current_palette
|
||||
from .chat_bubble_style import ThinkingIndicator
|
||||
from .chat_history_widget import ChatView
|
||||
from .chat_welcome import ChatWelcome
|
||||
from .composer_widget import Composer
|
||||
from ...ui.icons import collapse_right_icon, icon as app_icon
|
||||
from ...ui.osutil import is_image, open_path
|
||||
@@ -43,7 +44,13 @@ class ChatPanelLayoutMixin:
|
||||
cc = QVBoxLayout(chat_col)
|
||||
cc.setContentsMargins(0, 0, 0, 0)
|
||||
cc.setSpacing(0)
|
||||
# Man gioi thieu chiem dung cho cua khung chat va thay the no khi hoi
|
||||
# thoai con rong — hai thu khong bao gio cung hien.
|
||||
self.welcome = ChatWelcome()
|
||||
self.welcome.suggestion_picked.connect(self._use_suggestion)
|
||||
cc.addWidget(self.welcome, 1)
|
||||
cc.addWidget(self.chat_view, 1)
|
||||
self.chat_view.hide() # phien moi thi rong -> man gioi thieu di truoc
|
||||
self.thinking = ThinkingIndicator() # animated "working…" line while we wait
|
||||
cc.addWidget(self.thinking)
|
||||
self.center_split = QSplitter(Qt.Horizontal)
|
||||
@@ -148,3 +155,61 @@ class ChatPanelLayoutMixin:
|
||||
self.center_split.setChildrenCollapsible(False)
|
||||
self.center_split.setSizes([820, 220])
|
||||
on_language_changed(self._retranslate_base)
|
||||
|
||||
# ---- man gioi thieu ----------------------------------------------------
|
||||
def _use_suggestion(self, text: str) -> None:
|
||||
"""Thẻ gợi ý được bấm: ĐIỀN vào ô nhập, không gửi luôn.
|
||||
|
||||
Câu gợi ý là điểm bắt đầu — người dùng gần như luôn cần thêm chi tiết
|
||||
của riêng họ, và gửi ngay sẽ tiêu một lượt gọi model cho một câu hỏi
|
||||
chung chung.
|
||||
"""
|
||||
self.composer.input.setPlainText(text)
|
||||
self.composer.input.setFocus()
|
||||
|
||||
def show_welcome(self, show: bool) -> None:
|
||||
"""Bật màn giới thiệu (hội thoại rỗng) hoặc khung chat (đã có tin)."""
|
||||
welcome = getattr(self, "welcome", None)
|
||||
if welcome is None:
|
||||
return
|
||||
welcome.setVisible(show)
|
||||
self.chat_view.setVisible(not show)
|
||||
if show:
|
||||
welcome.refresh(**self._welcome_context())
|
||||
|
||||
def _welcome_context(self) -> dict:
|
||||
"""Dữ liệu cho dòng bối cảnh. Không biết thì trả -1, KHÔNG trả 0.
|
||||
|
||||
Hiện "0 tệp" khi người dùng vừa nhìn thấy tệp trong thư mục còn tệ hơn
|
||||
là bỏ mảnh đó khỏi dòng meta.
|
||||
"""
|
||||
from pathlib import Path as _P
|
||||
|
||||
ten = ""
|
||||
try:
|
||||
from ...core.projects import load_project
|
||||
project = load_project(self.project_id) if getattr(self, "project_id", "") else None
|
||||
ten = project.name if project is not None else ""
|
||||
except Exception: # noqa: BLE001
|
||||
ten = ""
|
||||
|
||||
so_tep = -1
|
||||
try:
|
||||
folder = self.workspace_dir()
|
||||
if folder is not None and _P(folder).is_dir():
|
||||
so_tep = sum(1 for f in _P(folder).rglob("*")
|
||||
if f.is_file() and f.suffix.lower() in self._INPUT_EXTS)
|
||||
except Exception: # noqa: BLE001
|
||||
so_tep = -1
|
||||
|
||||
so_skill = -1
|
||||
try:
|
||||
from ...core.skills import list_skills
|
||||
so_skill = sum(1 for sk in list_skills() if getattr(sk, "enabled", False))
|
||||
except Exception: # noqa: BLE001
|
||||
so_skill = -1
|
||||
|
||||
# Ten nguoi dung do cua so chinh giu (app.py truyen xuong MainWindow).
|
||||
window = self.window()
|
||||
return {"user_name": getattr(window, "_user_name", "") or "",
|
||||
"project": ten, "files": so_tep, "skills": so_skill}
|
||||
|
||||
Reference in New Issue
Block a user