From c9a45d343521c2932959a393f461d1dd889e93ee Mon Sep 17 00:00:00 2001 From: despiegk Date: Wed, 20 Aug 2025 04:32:30 +0200 Subject: [PATCH] ... --- README.md | 6 +- .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 189 bytes .../__pycache__/factory.cpython-313.pyc | Bin 0 -> 573 bytes .../logger/__pycache__/model.cpython-313.pyc | Bin 0 -> 4452 bytes .../logger/__pycache__/search.cpython-313.pyc | Bin 0 -> 7231 bytes herolib/core/logger/log_test.py | 33 +++-- herolib/core/logger/search.py | 140 ++++++++---------- .../__pycache__/__init__.cpython-313.pyc | Bin 186 -> 190 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 192 bytes .../__pycache__/texttools.cpython-313.pyc | Bin 0 -> 8963 bytes herolib/core/texttools/texttools.py | 2 + .../data/__pycache__/__init__.cpython-313.pyc | Bin 0 -> 182 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 186 -> 190 bytes pythonsetup/README.md | 60 ++++++++ pythonsetup/install.sh | 58 ++++++++ pythonsetup/pipenv.sh | 22 +++ pythonsetup/pyproject.toml | 23 +++ pythonsetup/start_server.sh | 70 +++++++++ pythonsetup/start_server_debug.sh | 70 +++++++++ 19 files changed, 385 insertions(+), 99 deletions(-) create mode 100644 herolib/core/logger/__pycache__/__init__.cpython-313.pyc create mode 100644 herolib/core/logger/__pycache__/factory.cpython-313.pyc create mode 100644 herolib/core/logger/__pycache__/model.cpython-313.pyc create mode 100644 herolib/core/logger/__pycache__/search.cpython-313.pyc create mode 100644 herolib/core/texttools/__pycache__/__init__.cpython-313.pyc create mode 100644 herolib/core/texttools/__pycache__/texttools.cpython-313.pyc create mode 100644 herolib/data/__pycache__/__init__.cpython-313.pyc create mode 100644 pythonsetup/README.md create mode 100755 pythonsetup/install.sh create mode 100755 pythonsetup/pipenv.sh create mode 100644 pythonsetup/pyproject.toml create mode 100755 pythonsetup/start_server.sh create mode 100755 pythonsetup/start_server_debug.sh diff --git a/README.md b/README.md index 2cb9a56..cd8fae5 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ has some usefull stuff as well ## Installation -You can install `herolib` directly from the Git repository using `uv pip` (or `pip`): +You can install `herolib` directly from the Git repository using `uv pip`: ```bash uv pip install git+https://git.ourworld.tf/herocode/herolib_python.git @@ -27,6 +27,10 @@ import herolib.core.loghandler.mylogging from herolib.core.loghandler.mylogging import MyLogger ``` +## how to integrate python in other projects + +see [Python Herolib Integration](pythonsetup/README.md) + ## Version Control This library follows standard Git version control practices. Releases can be managed by tagging specific commits in the Git repository. Users installing directly from the Git URL can specify a particular branch, tag, or commit hash to get a specific version. For example: diff --git a/herolib/core/logger/__pycache__/__init__.cpython-313.pyc b/herolib/core/logger/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c7e1fb1c1af209963d8f6ed3610c9ec3f94b09da GIT binary patch literal 189 zcmey&%ge<81YufBGeGoX5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa|LMerR!OQL%nX zYH>kkYI?SQa(+sxetKq!UVdp&d45q&ie5>Yenx6hK3D?8$jMBKFQ_cZ$j<|d1Gzv= zMXCBZ`RVDYMf&manR%Hd@$q^EmA5!-a`RJ4b5iY!Sb>&-98(Npd}L;1WGrF^vH&`i BGQ$7> literal 0 HcmV?d00001 diff --git a/herolib/core/logger/__pycache__/factory.cpython-313.pyc b/herolib/core/logger/__pycache__/factory.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..907292a81d8945241d7d258287047b11f97859ae GIT binary patch literal 573 zcmY*VF-yZx5PmN&NsDb21qDT1!HIn{auhbaQlcad&YL z{4;LyXeV9VD#hJDEg!ZM z5k`JX1bvQ0wF1<2O9G7(#V;0R!>K165~stHIN<(`<3%0r_<^vaA&epjJGSULJq}UY zP#_GhTJc!)qCr~66o-I2D2UfO-L@wp7~An!vH>4K9)*;4vXAbTOtNeDwa3zH_Tctn zl3RZ(tiEk-eHkoo&ImKiIg&`#GUe_<%2vB=^@1q0jOj&k`yb_3-tOc7hv~7BB?40U xX95LW3psQ$dxn%@$j@N|Q}yD>9=aK$lupUSjYa?f literal 0 HcmV?d00001 diff --git a/herolib/core/logger/__pycache__/model.cpython-313.pyc b/herolib/core/logger/__pycache__/model.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2182e871e23396767fcc403ea8e621de29c78595 GIT binary patch literal 4452 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 literal 0 HcmV?d00001 diff --git a/herolib/core/logger/log_test.py b/herolib/core/logger/log_test.py index 278b3a9..ce4b5fb 100644 --- a/herolib/core/logger/log_test.py +++ b/herolib/core/logger/log_test.py @@ -1,10 +1,11 @@ import unittest import os import shutil -from lib.core.logger.factory import new -from lib.core.logger.model import LogItemArgs, LogType, Logger # Import Logger class -from lib.data.ourtime.ourtime import new as ourtime_new, now as ourtime_now -from lib.core.pathlib.pathlib import get_file, ls, rmdir_all +from herolib.core.logger.factory import new +from herolib.core.logger.model import LogItemArgs, LogType, Logger # Import Logger class +from herolib.data.ourtime.ourtime import new as ourtime_new, now as ourtime_now +from herolib.core.pathlib.pathlib import get_file, ls, rmdir_all +from herolib.core.logger.search import search, SearchArgs class TestLogger(unittest.TestCase): def setUp(self): @@ -85,18 +86,18 @@ class TestLogger(unittest.TestCase): self.assertEqual(len(files), 2) # Expecting two files: 2022-12-05-20.log and 2022-12-05-22.log # Test search functionality - items_stdout = logger.search( + items_stdout = search(logger, SearchArgs( timestamp_from=ourtime_new('2022-11-01 20:14:35'), timestamp_to=ourtime_new('2025-11-01 20:14:35'), logtype=LogType.STDOUT - ) + )) self.assertEqual(len(items_stdout), 2) - items_error = logger.search( + items_error = search(logger, SearchArgs( timestamp_from=ourtime_new('2022-11-01 20:14:35'), timestamp_to=ourtime_new('2025-11-01 20:14:35'), logtype=LogType.ERROR - ) + )) self.assertEqual(len(items_error), 4) # Test specific log content @@ -115,34 +116,34 @@ class TestLogger(unittest.TestCase): self.assertTrue(found_stdout_log, "Expected stdout log content not found") # Test search by category - items_test_app = logger.search( + items_test_app = search(logger, SearchArgs( timestamp_from=ourtime_new('2022-11-01 20:14:35'), timestamp_to=ourtime_new('2025-11-01 20:14:35'), cat='test-app' - ) + )) self.assertEqual(len(items_test_app), 2) - items_error_test = logger.search( + items_error_test = search(logger, SearchArgs( timestamp_from=ourtime_new('2022-11-01 20:14:35'), timestamp_to=ourtime_new('2025-11-01 20:14:35'), cat='error-test' - ) + )) self.assertEqual(len(items_error_test), 4) # Test search by log content - items_with_aaa = logger.search( + items_with_aaa = search(logger, SearchArgs( timestamp_from=ourtime_new('2022-11-01 20:14:35'), timestamp_to=ourtime_new('2025-11-01 20:14:35'), log='aaa' - ) + )) self.assertEqual(len(items_with_aaa), 2) # Test search with timestamp range - items_specific_time = logger.search( + items_specific_time = search(logger, SearchArgs( timestamp_from=ourtime_new('2022-12-05 22:00:00'), timestamp_to=ourtime_new('2022-12-05 23:00:00'), logtype=LogType.ERROR - ) + )) self.assertEqual(len(items_specific_time), 2) diff --git a/herolib/core/logger/search.py b/herolib/core/logger/search.py index 4ac3e81..fe9b164 100644 --- a/herolib/core/logger/search.py +++ b/herolib/core/logger/search.py @@ -16,122 +16,98 @@ class SearchArgs: self.logtype = logtype self.maxitems = maxitems -def process(result: List[LogItem], current_item: LogItem, current_time: OurTime, - args: SearchArgs, from_time: int, to_time: int): - # Add previous item if it matches filters - log_epoch = current_item.timestamp.unix() - if log_epoch < from_time or log_epoch > to_time: - return - - cat_match = (args.cat == '' or current_item.cat.strip() == args.cat) - log_match = (args.log == '' or args.log.lower() in current_item.log.lower()) - logtype_match = (args.logtype is None or current_item.logtype == args.logtype) - - if cat_match and log_match and logtype_match: - result.append(current_item) - def search(l: Logger, args_: SearchArgs) -> List[LogItem]: args = args_ - # Format category (max 10 chars, ascii only) args.cat = name_fix(args.cat) if len(args.cat) > 10: raise ValueError('category cannot be longer than 10 chars') - timestamp_from = args.timestamp_from if args.timestamp_from else OurTime() - timestamp_to = args.timestamp_to if args.timestamp_to else OurTime() + from_time = args.timestamp_from.unix() if args.timestamp_from else 0 + to_time = args.timestamp_to.unix() if args.timestamp_to else ourtime_new('2100-01-01').unix() - # Get time range - from_time = timestamp_from.unix() - to_time = timestamp_to.unix() if from_time > to_time: - raise ValueError(f'from_time cannot be after to_time: {from_time} < {to_time}') - + raise ValueError(f'from_time cannot be after to_time: {from_time} > {to_time}') + result: List[LogItem] = [] - - # Find log files in time range + if not os.path.exists(l.path.path): + return [] files = sorted(os.listdir(l.path.path)) for file in files: if not file.endswith('.log'): continue - # Parse dayhour from filename - dayhour = file[:-4] # remove .log + dayhour = file[:-4] try: file_time = ourtime_new(dayhour) except ValueError: - continue # Skip if filename is not a valid time format - - current_time = OurTime() - current_item = LogItem(OurTime(), "", "", LogType.STDOUT) # Initialize with dummy values - collecting = False - - # Skip if file is outside time range - if file_time.unix() < from_time or file_time.unix() > to_time: continue - # Read and parse log file - content = "" + file_hour_start_unix = file_time.unix() + file_hour_end_unix = file_hour_start_unix + 3599 + if file_hour_end_unix < from_time or file_hour_start_unix > to_time: + continue + try: with open(os.path.join(l.path.path, file), 'r') as f: content = f.read() except FileNotFoundError: continue - lines = content.split('\n') + current_time = None + current_item = None - for line in lines: + for line in content.splitlines(): if len(result) >= args.maxitems: - return result + break - line_trim = line.strip() - if not line_trim: + if not line.strip() and current_item: + if from_time <= current_item.timestamp.unix() <= to_time: + if (not args.cat or args.cat == current_item.cat) and \ + (not args.log or args.log.lower() in current_item.log.lower()) and \ + (args.logtype is None or args.logtype == current_item.logtype): + result.append(current_item) + current_item = None continue - # Check if this is a timestamp line - if not (line.startswith(' ') or line.startswith('E')): + if not line.startswith(' ') and not line.startswith('E'): + if current_item: + if from_time <= current_item.timestamp.unix() <= to_time: + if (not args.cat or args.cat == current_item.cat) and \ + (not args.log or args.log.lower() in current_item.log.lower()) and \ + (args.logtype is None or args.logtype == current_item.logtype): + result.append(current_item) try: - current_time = ourtime_new(line_trim) + current_time = ourtime_new(f"{file_time.day()} {line.strip()}") + current_item = None except ValueError: - continue # Skip if not a valid timestamp line + current_time = None + current_item = None + elif current_time: + if line.startswith(' ') or line.startswith('E'): + if len(line) > 14 and line[13] == '-': + if current_item: + if from_time <= current_item.timestamp.unix() <= to_time: + if (not args.cat or args.cat == current_item.cat) and \ + (not args.log or args.log.lower() in current_item.log.lower()) and \ + (args.logtype is None or args.logtype == current_item.logtype): + result.append(current_item) + + is_error = line.startswith('E') + logtype = LogType.ERROR if is_error else LogType.STDOUT + cat = line[2:12].strip() + log_content = line[15:] - if collecting: - process(result, current_item, current_time, args, from_time, to_time) - collecting = False - continue - - if collecting and len(line) > 14 and line[13] == '-': - process(result, current_item, current_time, args, from_time, to_time) - collecting = False - - # Parse log line - is_error = line.startswith('E') - if not collecting: - # Start new item - cat_start = 2 - cat_end = 12 - log_start = 15 - - if len(line) < log_start: - continue # Line too short to contain log content - - current_item = LogItem( - timestamp=current_time, - cat=line[cat_start:cat_end].strip(), - log=line[log_start:].strip(), - logtype=LogType.ERROR if is_error else LogType.STDOUT - ) - collecting = True - else: - # Continuation line - if len(line_trim) < 16: # Check for minimum length for continuation line - current_item.log += '\n' + line_trim - else: - current_item.log += '\n' + line[15:].strip() # Use strip for continuation lines - - # Add last item if collecting - if collecting: - process(result, current_item, current_time, args, from_time, to_time) + current_item = LogItem(timestamp=current_time, cat=cat, log=log_content.strip(), logtype=logtype) + elif current_item: + current_item.log += "\n" + (line[15:] if len(line) >15 else line) + + if current_item: + if from_time <= current_item.timestamp.unix() <= to_time: + if (not args.cat or args.cat == current_item.cat) and \ + (not args.log or args.log.lower() in current_item.log.lower()) and \ + (args.logtype is None or args.logtype == current_item.logtype): + result.append(current_item) return result \ No newline at end of file diff --git a/herolib/core/pathlib/__pycache__/__init__.cpython-313.pyc b/herolib/core/pathlib/__pycache__/__init__.cpython-313.pyc index 4123a7bae65b323a112248425f55e146181aef53..66f38affc378adc8780f47c08ac2ce434bd9f9b8 100644 GIT binary patch delta 32 mcmdnRxQ~(hGcPX}0}zC1EuF}1%osb--j*dJwJ3jLjU51pdI>P{wB#AY&>+I)f&o-%5reCLr%KNa|L+erR!OQL%nX zYH>kkYI?SQa(+sxetKq!UVdp&d45q&ie5>Yenx6hK3D?8$jMBKFQ_cZ$j<|d1Gzv= zMXCBFsTCz9`T04;`tk9Zd6^~g@p=W7w>WHa^HWN5QtgUZf%bviQw(B!WM*V!EMf+- E0Q(O#JOBUy literal 0 HcmV?d00001 diff --git a/herolib/core/texttools/__pycache__/texttools.cpython-313.pyc b/herolib/core/texttools/__pycache__/texttools.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a5c11fd8112404ab54cb7205e2d417b47abed76 GIT binary patch literal 8963 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 str: # VLang's name_fix converts '-' to '_' and cleans up special chars. diff --git a/herolib/data/__pycache__/__init__.cpython-313.pyc b/herolib/data/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a0f778726ce8908f504253e9c52febe020fa728 GIT binary patch literal 182 zcmey&%ge<81YufBGeGoX5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa|LoerR!OQL%nX zYH>kkYI?SQa(+sxetKq!UVdp&d45q&ie5>Yenx6hK3D?8$jMBKFQ_cZ$j<|d1G)Ms vi6x2p@$s2?nI-Y@dIgoYIBatBQ%ZAE?TT1|wt!qw3}Sp_W@Kb6Vg|ARsXH(J literal 0 HcmV?d00001 diff --git a/herolib/data/ourtime/__pycache__/__init__.cpython-313.pyc b/herolib/data/ourtime/__pycache__/__init__.cpython-313.pyc index b15cd9738a5e294a0fa07ebf40bcabaec67212cb..1121c511f88185b934f1fbbb7732e68b69931f00 100644 GIT binary patch delta 32 mcmdnRxQ~(hGcPX}0}zC1EuF}1%osb--j*dJwJ3jLjU51pdI /dev/null; then + echo -e "${YELLOW}⚠️ uv is not installed. Installing uv...${NC}" + curl -LsSf https://astral.sh/uv/install.sh | sh + source $HOME/.cargo/env + echo -e "${GREEN}✅ uv installed${NC}" +fi + +echo -e "${GREEN}✅ uv found${NC}" + +# Initialize uv project if not already done +if [ ! -f "pyproject.toml" ]; then + echo -e "${YELLOW}⚠️ No pyproject.toml found. Initializing uv project...${NC}" + uv init --no-readme --python 3.13 + echo -e "${GREEN}✅ uv project initialized${NC}" +fi + +# Sync dependencies +echo -e "${YELLOW}📦 Installing dependencies with uv...${NC}" +uv sync +if [ -d "$HOME/code/git.ourworld.tf/herocode/herolib_python/herolib" ]; then + echo -e "${GREEN}✅ Found local herolib, installing...${NC}" + uv pip install -e "$HOME/code/git.ourworld.tf/herocode/herolib_python" +else + echo -e "${YELLOW}📦 Local herolib not found, installing from git...${NC}" + uv pip install herolib@git+https://git.ourworld.tf/herocode/herolib_python.git --force-reinstall --no-cache-dir +fi +echo -e "${GREEN}✅ Dependencies installed${NC}" + +# Create necessary directories +mkdir -p static/css static/js static/images +mkdir -p templates +mkdir -p md + +echo -e "${GREEN}✅ Directory structure verified${NC}" + +echo -e "${GREEN}🎉 Installation complete! You can now run start_server.sh${NC}" \ No newline at end of file diff --git a/pythonsetup/pipenv.sh b/pythonsetup/pipenv.sh new file mode 100755 index 0000000..e3c4a02 --- /dev/null +++ b/pythonsetup/pipenv.sh @@ -0,0 +1,22 @@ +#!/bin/bash +export PYTHONPATH=$PYTHONPATH:$(pwd)/src + + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +echo "Setting up KnowledgeCenter environment in: $SCRIPT_DIR" + +# Create virtual environment if it doesn't exist +if [ ! -d ".venv" ]; then + echo "📦 Creating Python virtual environment..." + uv venv + echo "✅ Virtual environment created" +else + echo "✅ Virtual environment already exists" +fi + +# Activate virtual environment +echo "🔄 Activating virtual environment..." +source .venv/bin/activate diff --git a/pythonsetup/pyproject.toml b/pythonsetup/pyproject.toml new file mode 100644 index 0000000..edc5eea --- /dev/null +++ b/pythonsetup/pyproject.toml @@ -0,0 +1,23 @@ +[project] +name = "KnowledgeCenter" +version = "0.1.0" +description = "Add your description here" +requires-python = ">=3.13" +dependencies = [ + "beautifulsoup4>=4.13.4", + "flask>=2.3.3", + "markdown>=3.5.1", + "Werkzeug>=3.1.3", + "peewee>=3.17.0", + "pygments>=2.16.1", + "toml", + "flask_socketio", + "eventlet", + "fastapi>=0.104.0", + "uvicorn>=0.24.0", + "python-multipart>=0.0.6", + "requests>=2.31.0", + "herolib @ git+https://git.ourworld.tf/herocode/herolib_python.git", + "pudb", + "ipython" +] diff --git a/pythonsetup/start_server.sh b/pythonsetup/start_server.sh new file mode 100755 index 0000000..8df79ec --- /dev/null +++ b/pythonsetup/start_server.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# KnowledgeCenter Web Server Startup Script +# This script starts the Flask web server on port 9922 for PRODUCTION + +set -e # Exit on any error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +source pipenv.sh + +echo -e "${BLUE}🚀 KnowledgeCenter Web Server Startup (PRODUCTION)${NC}" +echo "=================================================" + +# Check if uv is installed +# Check if port 9922 is available +if lsof -Pi :9922 -sTCP:LISTEN -t >/dev/null 2>&1; then + echo -e "${YELLOW}⚠️ Port 9922 is already in use. Attempting to stop existing process...${NC}" + PID=$(lsof -ti:9922) + if [ ! -z "$PID" ]; then + kill -9 $PID 2>/dev/null || true + sleep 2 + echo -e "${GREEN}✅ Existing process stopped${NC}" + fi +fi + +# Set environment variables for production +export FLASK_APP=src/app.py +export FLASK_ENV=production +export FLASK_DEBUG=0 + +# Display startup information +echo "" +echo -e "${BLUE}📋 Server Information:${NC}" +echo " • Application: KnowledgeCenter Interest Registration" +echo " • Port: 9922" +echo " • URL: http://localhost:9922" +echo " • Environment: Production" +echo " • Debug Mode: Disabled" +echo "" + +# Function to handle cleanup on exit +cleanup() { + echo -e "\n${YELLOW}🛑 Shutting down server...${NC}" + exit 0 +} + +# Set trap for cleanup +trap cleanup SIGINT SIGTERM + +# Start the Flask development server +echo -e "${GREEN}🌟 Starting KnowledgeCenter web server...${NC}" +echo -e "${BLUE}📡 Server will be available at: http://localhost:9922${NC}" +echo -e "${YELLOW}💡 Press Ctrl+C to stop the server${NC}" +echo "" + +# Start the server with uv, specifying production config +uv run python src/app.py --cfg prod --port 9922 --host 0.0.0.0 + +# This line should not be reached unless the server exits +echo -e "${RED}❌ Server stopped unexpectedly${NC}" diff --git a/pythonsetup/start_server_debug.sh b/pythonsetup/start_server_debug.sh new file mode 100755 index 0000000..fcdc507 --- /dev/null +++ b/pythonsetup/start_server_debug.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# KnowledgeCenter Web Server Startup Script +# This script starts the Flask web server on port 9922 for PRODUCTION + +set -e # Exit on any error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +source pipenv.sh + +echo -e "${BLUE}🚀 KnowledgeCenter Web Server Startup (DEVELOPMENT/DEBUG)${NC}" +echo "=================================================" + +# Check if uv is installed +# Check if port 9922 is available +if lsof -Pi :9922 -sTCP:LISTEN -t >/dev/null 2>&1; then + echo -e "${YELLOW}⚠️ Port 9922 is already in use. Attempting to stop existing process...${NC}" + PID=$(lsof -ti:9922) + if [ ! -z "$PID" ]; then + kill -9 $PID 2>/dev/null || true + sleep 2 + echo -e "${GREEN}✅ Existing process stopped${NC}" + fi +fi + +# Set environment variables for production +export FLASK_APP=src/app.py +export FLASK_ENV=development +export FLASK_DEBUG=1 + +# Display startup information +echo "" +echo -e "${BLUE}📋 Server Information:${NC}" +echo " • Application: KnowledgeCenter Interest Registration" +echo " • Port: 9922" +echo " • URL: http://localhost:9922" +echo " • Environment: Development" +echo " • Debug Mode: Enabled" +echo "" + +# Function to handle cleanup on exit +cleanup() { + echo -e "\n${YELLOW}🛑 Shutting down server...${NC}" + exit 0 +} + +# Set trap for cleanup +trap cleanup SIGINT SIGTERM + +# Start the Flask development server +echo -e "${GREEN}🌟 Starting KnowledgeCenter web server...${NC}" +echo -e "${BLUE}📡 Server will be available at: http://localhost:9922${NC}" +echo -e "${YELLOW}💡 Press Ctrl+C to stop the server${NC}" +echo "" + +# Start the server with uv, specifying production config +uv run python src/app.py --cfg dev --port 9922 --host 0.0.0.0 --debug + +# This line should not be reached unless the server exits +echo -e "${RED}❌ Server stopped unexpectedly${NC}"