-
Notifications
You must be signed in to change notification settings - Fork 460
fix build webui #840
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix build webui #840
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,19 @@ | ||
| recursive-include ms_agent/tools/code_interpreter *.ttf | ||
| recursive-include ms_agent/utils *.tiktoken | ||
| recursive-include ms_agent/utils/nltk *.zip | ||
| recursive-include ms_agent/ *.yaml | ||
| include README.md | ||
| include LICENSE | ||
| include requirements.txt | ||
| recursive-include requirements *.txt | ||
|
|
||
| # Include projects | ||
| recursive-include projects * | ||
|
|
||
| # Include webui backend | ||
| recursive-include webui/backend *.py | ||
|
|
||
| # Include webui frontend dist (will be built during setup) | ||
| recursive-include webui/frontend/dist * | ||
| recursive-include projects * | ||
|
|
||
| # Exclude development files | ||
| global-exclude *.pyc | ||
| global-exclude __pycache__ | ||
| global-exclude .DS_Store | ||
| global-exclude *.so | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,9 +17,10 @@ def readme(): | |
|
|
||
|
|
||
| def get_version(): | ||
| namespace = {} | ||
| with open(version_file, 'r', encoding='utf-8') as f: | ||
| exec(compile(f.read(), version_file, 'exec')) | ||
| return locals()['__version__'] | ||
| exec(compile(f.read(), version_file, 'exec'), namespace) | ||
| return namespace['__version__'] | ||
|
|
||
|
|
||
| def parse_requirements(fname='requirements.txt', with_version=True): | ||
|
|
@@ -126,16 +127,101 @@ def run(self): | |
|
|
||
| # Copy the repository root's `projects/` into the build directory's `ms_agent/projects/` | ||
| src = os.path.join(os.path.dirname(__file__), 'projects') | ||
| if not os.path.isdir(src): | ||
| if os.path.isdir(src): | ||
| dst = os.path.join(self.build_lib, 'ms_agent', 'projects') | ||
| os.makedirs(os.path.dirname(dst), exist_ok=True) | ||
|
|
||
| if os.path.exists(dst): | ||
| shutil.rmtree(dst) | ||
|
|
||
| shutil.copytree(src, dst) | ||
|
|
||
| # Build and copy webui | ||
| self._build_and_copy_webui() | ||
|
|
||
| def _build_and_copy_webui(self): | ||
| """Build frontend and copy webui files to build directory""" | ||
| import subprocess | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| repo_root = os.path.dirname(__file__) | ||
| webui_src = os.path.join(repo_root, 'webui') | ||
|
|
||
| if not os.path.isdir(webui_src): | ||
| print( | ||
| 'Warning: webui directory not found, skipping webui packaging') | ||
| return | ||
|
|
||
| dst = os.path.join(self.build_lib, 'ms_agent', 'projects') | ||
| os.makedirs(os.path.dirname(dst), exist_ok=True) | ||
| frontend_src = os.path.join(webui_src, 'frontend') | ||
| backend_src = os.path.join(webui_src, 'backend') | ||
|
|
||
| if os.path.exists(dst): | ||
| shutil.rmtree(dst) | ||
| # Check if npm is available | ||
| try: | ||
| subprocess.run(['npm', '--version'], | ||
| capture_output=True, | ||
| check=True, | ||
| timeout=5) | ||
| npm_available = True | ||
| except (subprocess.CalledProcessError, FileNotFoundError, | ||
| subprocess.TimeoutExpired): | ||
| npm_available = False | ||
| print( | ||
| 'Warning: npm not found, cannot build frontend. WebUI may not work properly.' | ||
| ) | ||
|
|
||
| shutil.copytree(src, dst) | ||
| # Build frontend if npm is available | ||
| if npm_available and os.path.isdir(frontend_src): | ||
| print('Building frontend with npm...') | ||
|
|
||
| # Install dependencies if needed | ||
| node_modules = os.path.join(frontend_src, 'node_modules') | ||
| if not os.path.exists(node_modules): | ||
| print('Installing frontend dependencies...') | ||
| try: | ||
| subprocess.run(['npm', 'install'], | ||
| cwd=frontend_src, | ||
| check=True, | ||
| timeout=300) | ||
| except (subprocess.CalledProcessError, | ||
| subprocess.TimeoutExpired) as e: | ||
| print(f'Warning: npm install failed: {e}') | ||
| return | ||
|
|
||
| # Build frontend | ||
| try: | ||
| subprocess.run(['npm', 'run', 'build'], | ||
| cwd=frontend_src, | ||
| check=True, | ||
| timeout=300) | ||
| print('Frontend built successfully') | ||
| except (subprocess.CalledProcessError, | ||
| subprocess.TimeoutExpired) as e: | ||
| print(f'Warning: npm build failed: {e}') | ||
| return | ||
|
|
||
| # Copy webui to build directory | ||
| webui_dst = os.path.join(self.build_lib, 'ms_agent', 'webui') | ||
|
|
||
| # Copy backend | ||
| if os.path.isdir(backend_src): | ||
| backend_dst = os.path.join(webui_dst, 'backend') | ||
| if os.path.exists(backend_dst): | ||
| shutil.rmtree(backend_dst) | ||
| shutil.copytree(backend_src, backend_dst) | ||
| print(f'Copied backend to {backend_dst}') | ||
|
|
||
| # Copy frontend dist (built files) | ||
| frontend_dist_src = os.path.join(frontend_src, 'dist') | ||
| if os.path.isdir(frontend_dist_src): | ||
| frontend_dst = os.path.join(webui_dst, 'frontend', 'dist') | ||
| os.makedirs(os.path.dirname(frontend_dst), exist_ok=True) | ||
| if os.path.exists(frontend_dst): | ||
| shutil.rmtree(frontend_dst) | ||
| shutil.copytree(frontend_dist_src, frontend_dst) | ||
| print(f'Copied frontend dist to {frontend_dst}') | ||
| else: | ||
| print( | ||
| 'Warning: frontend dist not found, WebUI may not work in production mode' | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
|
|
@@ -171,7 +257,11 @@ def run(self): | |
| include_package_data=True, | ||
| cmdclass={'build_py': build_py}, | ||
| package_data={ | ||
| 'ms_agent': ['projects/**/*'], | ||
| 'ms_agent': [ | ||
| 'projects/**/*', | ||
| 'webui/backend/**/*', | ||
| 'webui/frontend/dist/**/*', | ||
| ], | ||
| '': ['*.h', '*.cpp', '*.cu'], | ||
| }, | ||
| classifiers=[ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,7 +37,7 @@ import { | |
| AccountTree as WorkflowIcon, | ||
| } from '@mui/icons-material'; | ||
| import { motion, AnimatePresence } from 'framer-motion'; | ||
| import { useSession, Message } from '../context/SessionContext'; | ||
| import { useSession, Message, Session } from '../context/SessionContext'; | ||
| import WorkflowProgress from './WorkflowProgress'; | ||
| import FileProgress from './FileProgress'; | ||
| import LogViewer from './LogViewer'; | ||
|
|
@@ -90,10 +90,19 @@ const ConversationView: React.FC<ConversationViewProps> = ({ showLogs }) => { | |
| const messagesEndRef = useRef<HTMLDivElement>(null); | ||
| const inputRef = useRef<HTMLInputElement>(null); | ||
| const [fileError, setFileError] = useState<string | null>(null); | ||
| const [fileLang, setFileLang] = useState('text'); | ||
| const [fileUrl, setFileUrl] = useState<string | null>(null); | ||
| const [fileKind, setFileKind] = useState<'text' | 'image' | 'video' | 'audio'>('text'); | ||
|
|
||
| // Check if waiting for user input | ||
| const isWaitingForInput = React.useMemo(() => { | ||
| return messages.some(m => m.type === 'waiting_input'); | ||
| }, [messages]); | ||
|
|
||
| // Check if input should be enabled | ||
| const inputEnabled = React.useMemo(() => { | ||
| return !isLoading || isWaitingForInput; | ||
| }, [isLoading, isWaitingForInput]); | ||
|
|
||
| const getFileKind = (fname: string): 'text' | 'image' | 'video' | 'audio' => { | ||
| const ext = fname.split('.').pop()?.toLowerCase() || ''; | ||
| if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'].includes(ext)) return 'image'; | ||
|
|
@@ -198,7 +207,6 @@ const ConversationView: React.FC<ConversationViewProps> = ({ showLogs }) => { | |
|
|
||
| const data = await response.json(); | ||
| setFileContent(data.content); | ||
| setFileLang(data.language || 'text'); | ||
| setFileUrl(null); | ||
| return; | ||
| } | ||
|
|
@@ -208,7 +216,6 @@ const ConversationView: React.FC<ConversationViewProps> = ({ showLogs }) => { | |
| `/api/files/stream?path=${encodeURIComponent(path)}&session_id=${encodeURIComponent(sid || '')}`; | ||
| setFileUrl(streamUrl); | ||
| setFileContent(null); | ||
| setFileLang(kind); | ||
| } catch (err) { | ||
| setFileError(err instanceof Error ? err.message : 'Failed to load file'); | ||
| } finally { | ||
|
|
@@ -873,7 +880,7 @@ interface MessageBubbleProps { | |
| } | ||
|
|
||
| const MessageBubble: React.FC<MessageBubbleProps> = ({ | ||
| message, isStreaming, sessionStatus, completedSteps, | ||
| message, isStreaming, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While you've removed |
||
| showRetry, onRetry | ||
| }) => { | ||
| const theme = useTheme(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current
MANIFEST.inconfiguration will likely create a broken source distribution (sdist). It includeswebui/frontend/dist, which is a build artifact, but omits the frontend source files (webui/frontend/src,webui/frontend/package.json, etc.).When building from a source distribution, the
setup.pyscript needs the frontend source files to runnpm installandnpm run build. Without them, the build will fail.To fix this, you should include the frontend source files and exclude build artifacts and dependencies from the
sdist.