Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 110
Control center#567
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
Merged
Uh oh!
There was an error while loading. Please reload this page.
Merged
Control center #567
Changes from all commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
602d0ad
added group status (active, locked, upload disabled, and inactive)
paullizer 64c2df0
added bulk member upload via csv for groups
paullizer ae7d1f0
add document metadata modified activity log tracking
paullizer 59156be
activity logging for members deleted from groups
paullizer 613144f
added group activity timeline
paullizer c801dea
added notification system
paullizer 2da6ba7
added notifications for document upload to workspaces
paullizer 71f1357
fixed badge sizing
paullizer 6287da4
fixed url link
paullizer a8aa92a
fixed badge to not show with zero notifications
paullizer 30287e0
Updated notification system
paullizer 7ed89a1
Updated approval system
paullizer 6cfa925
updated approval workflow
paullizer 5f90672
updated notification workflow
paullizer 6d64dba
Fixed set active bug on my public workspace page
paullizer 30792e4
Added user retention policy, updated user profile page with dashboard…
paullizer d3339af
adding speed to text for chat UI
paullizer db4fadf
updated the speech wave form and input field
paullizer d0d482d
updated to transcribe entire recording
paullizer c2d6eaa
fixed bug creating new conversation with auto-send
paullizer 059f1f1
add mic permissions
paullizer 35cf17e
added stream token tracking
paullizer 2ee7aae
Added public workspace reporting
paullizer ebb9e77
Updated AI search sizing analysis
paullizer e442c76
added management for public workspaces
paullizer a42800d
improved public workspace management includes stats and bulk actions
paullizer 5a55f9a
updated groups dashboard for owners and admins with stats and bulk ac…
paullizer 2feb9ec
added voice for ai to talk with users in chats
paullizer f68ce76
Auto Voice Response
paullizer 6ccaea9
for speech service, added 429 randomized response pattern to prevent …
paullizer 75c5472
updated admin settings for speech services and fixed dark mode for ra…
paullizer 2d44e42
updated video extraction card
paullizer f1ea4c3
Added Control Center Admin and Dashboard Reader roles
paullizer d6ad5be
updated feedback and safety decorators so admins work unless required…
paullizer 9f8250b
Updated and Validated logic for admin roles; control center, safety, …
paullizer a2ddf48
added support for control center admin and dashboard reader
paullizer f78c48c
Development (#566)
paullizer b9cb93e
updated tool tip to better inform user on status of ai response
paullizer 17ea6ab
improve query parameters detection for swagger
paullizer d4f1a95
updated visual cue showing the ai is talking to the user
paullizer ef393b8
moved duplicates to shared js
paullizer 0c2cc8a
replaced alert with toast.
paullizer 5fba0bb
fixed and added log_event to exceptions
paullizer 1a00ced
added @user_required and improved swagger generation
paullizer 0c88dc6
Update route_frontend_profile.py
paullizer 8c417ce
fixed swagger generation bug on affecting two apis
paullizer f9754ec
returned keyvault to admin settings ui
paullizer 108dc40
Fixed bug when running local js
paullizer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -36,6 +36,7 @@ | ||
| from route_frontend_public_workspaces import * | ||
| from route_frontend_safety import * | ||
| from route_frontend_feedback import * | ||
| from route_frontend_notifications import * | ||
| from route_backend_chats import * | ||
| from route_backend_conversations import * | ||
| @@ -50,20 +51,30 @@ | ||
| from route_backend_prompts import * | ||
| from route_backend_group_prompts import * | ||
| from route_backend_control_center import * | ||
| from route_backend_notifications import * | ||
| from route_backend_retention_policy import * | ||
| from route_backend_plugins import bpap as admin_plugins_bp, bpdp as dynamic_plugins_bp | ||
| from route_backend_agents import bpa as admin_agents_bp | ||
| from route_backend_public_workspaces import * | ||
| from route_backend_public_documents import * | ||
| from route_backend_public_prompts import * | ||
| from route_backend_speech import register_route_backend_speech | ||
| from route_backend_tts import register_route_backend_tts | ||
| from route_enhanced_citations import register_enhanced_citations_routes | ||
| from plugin_validation_endpoint import plugin_validation_bp | ||
| from route_openapi import register_openapi_routes | ||
| from route_migration import bp_migration | ||
| from route_plugin_logging import bpl as plugin_logging_bp | ||
| from functions_debug import debug_print | ||
| from opentelemetry.instrumentation.flask import FlaskInstrumentor | ||
| app = Flask(__name__, static_url_path='/static', static_folder='static') | ||
| disable_flask_instrumentation = os.environ.get("DISABLE_FLASK_INSTRUMENTATION", "0") | ||
| if not (disable_flask_instrumentation == "1" or disable_flask_instrumentation.lower() == "true"): | ||
| FlaskInstrumentor().instrument_app(app) | ||
| app.config['EXECUTOR_TYPE'] = EXECUTOR_TYPE | ||
| app.config['EXECUTOR_MAX_WORKERS'] = EXECUTOR_MAX_WORKERS | ||
| executor = Executor() | ||
| @@ -95,6 +106,12 @@ | ||
| # Register Enhanced Citations routes | ||
| register_enhanced_citations_routes(app) | ||
| # Register Speech routes | ||
| register_route_backend_speech(app) | ||
| # Register TTS routes | ||
| register_route_backend_tts(app) | ||
| # Register Swagger documentation routes | ||
| from swagger_wrapper import register_swagger_routes | ||
| register_swagger_routes(app) | ||
| @@ -121,38 +138,54 @@ def configure_sessions(settings): | ||
| redis_auth_type = settings.get('redis_auth_type', 'key').strip().lower() | ||
| if redis_url: | ||
| app.config['SESSION_TYPE'] = 'redis' | ||
| if redis_auth_type == 'managed_identity': | ||
| print("Redis enabled using Managed Identity") | ||
| from config import get_redis_cache_infrastructure_endpoint | ||
| credential = DefaultAzureCredential() | ||
| redis_hostname = redis_url.split('.')[0] | ||
| cache_endpoint = get_redis_cache_infrastructure_endpoint(redis_hostname) | ||
| token = credential.get_token(cache_endpoint) | ||
| app.config['SESSION_REDIS'] = Redis( | ||
| host=redis_url, | ||
| port=6380, | ||
| db=0, | ||
| password=token.token, | ||
| ssl=True | ||
| ) | ||
| else: | ||
| redis_key = settings.get('redis_key', '').strip() | ||
| print("Redis enabled using Access Key") | ||
| app.config['SESSION_REDIS'] = Redis( | ||
| host=redis_url, | ||
| port=6380, | ||
| db=0, | ||
| password=redis_key, | ||
| ssl=True | ||
| ) | ||
| redis_client = None | ||
| try: | ||
| if redis_auth_type == 'managed_identity': | ||
| print("Redis enabled using Managed Identity") | ||
| from config import get_redis_cache_infrastructure_endpoint | ||
| credential = DefaultAzureCredential() | ||
| redis_hostname = redis_url.split('.')[0] | ||
| cache_endpoint = get_redis_cache_infrastructure_endpoint(redis_hostname) | ||
| token = credential.get_token(cache_endpoint) | ||
| redis_client = Redis( | ||
| host=redis_url, | ||
| port=6380, | ||
| db=0, | ||
| password=token.token, | ||
| ssl=True, | ||
| socket_connect_timeout=5, | ||
| socket_timeout=5 | ||
| ) | ||
| else: | ||
| redis_key = settings.get('redis_key', '').strip() | ||
| print("Redis enabled using Access Key") | ||
| redis_client = Redis( | ||
| host=redis_url, | ||
| port=6380, | ||
| db=0, | ||
| password=redis_key, | ||
| ssl=True, | ||
| socket_connect_timeout=5, | ||
| socket_timeout=5 | ||
| ) | ||
| # Test the connection | ||
| redis_client.ping() | ||
| print("✅ Redis connection successful") | ||
| app.config['SESSION_TYPE'] = 'redis' | ||
| app.config['SESSION_REDIS'] = redis_client | ||
| except Exception as redis_error: | ||
| print(f"⚠️ WARNING: Redis connection failed: {redis_error}") | ||
| print("Falling back to filesystem sessions for reliability") | ||
| app.config['SESSION_TYPE'] = 'filesystem' | ||
| else: | ||
| print("Redis enabled but URL missing; falling back to filesystem.") | ||
| app.config['SESSION_TYPE'] = 'filesystem' | ||
| else: | ||
| app.config['SESSION_TYPE'] = 'filesystem' | ||
| except Exception as e: | ||
| print(f"WARNING: Session configuration error; falling back to filesystem: {e}") | ||
| print(f"⚠️ WARNING: Session configuration error; falling back to filesystem: {e}") | ||
| app.config['SESSION_TYPE'] = 'filesystem' | ||
| # Initialize session interface | ||
| @@ -242,6 +275,86 @@ def check_logging_timers(): | ||
| timer_thread.start() | ||
| print("Logging timer background task started.") | ||
| # Background task to check for expired approval requests | ||
| def check_expired_approvals(): | ||
| """Background task that checks for expired approval requests and auto-denies them""" | ||
| while True: | ||
| try: | ||
| from functions_approvals import auto_deny_expired_approvals | ||
| denied_count = auto_deny_expired_approvals() | ||
| if denied_count > 0: | ||
| print(f"Auto-denied {denied_count} expired approval request(s).") | ||
| except Exception as e: | ||
| print(f"Error in approval expiration check: {e}") | ||
| # Check every 6 hours (21600 seconds) | ||
| time.sleep(21600) | ||
| # Start the approval expiration check thread | ||
| approval_thread = threading.Thread(target=check_expired_approvals, daemon=True) | ||
| approval_thread.start() | ||
| print("Approval expiration background task started.") | ||
| # Background task to check retention policy execution time | ||
| def check_retention_policy(): | ||
| """Background task that executes retention policy at scheduled time""" | ||
| while True: | ||
| try: | ||
| settings = get_settings() | ||
| # Check if any retention policy is enabled | ||
| personal_enabled = settings.get('enable_retention_policy_personal', False) | ||
| group_enabled = settings.get('enable_retention_policy_group', False) | ||
| public_enabled = settings.get('enable_retention_policy_public', False) | ||
| if personal_enabled or group_enabled or public_enabled: | ||
| current_time = datetime.now(timezone.utc) | ||
| execution_hour = settings.get('retention_policy_execution_hour', 2) | ||
| # Check if we're in the execution hour | ||
| if current_time.hour == execution_hour: | ||
| # Check if we haven't run today yet | ||
| last_run = settings.get('retention_policy_last_run') | ||
| should_run = False | ||
| if last_run: | ||
| try: | ||
| last_run_dt = datetime.fromisoformat(last_run) | ||
| # Run if last run was more than 23 hours ago | ||
| if (current_time - last_run_dt).total_seconds() > (23 * 3600): | ||
| should_run = True | ||
| except: | ||
| should_run = True | ||
| else: | ||
| should_run = True | ||
| if should_run: | ||
| print(f"Executing scheduled retention policy at {current_time.isoformat()}") | ||
| from functions_retention_policy import execute_retention_policy | ||
| results = execute_retention_policy(manual_execution=False) | ||
| if results.get('success'): | ||
| print(f"Retention policy execution completed: " | ||
| f"{results['personal']['conversations']} personal conversations, " | ||
| f"{results['personal']['documents']} personal documents, " | ||
| f"{results['group']['conversations']} group conversations, " | ||
| f"{results['group']['documents']} group documents, " | ||
| f"{results['public']['conversations']} public conversations, " | ||
| f"{results['public']['documents']} public documents deleted.") | ||
| else: | ||
| print(f"Retention policy execution failed: {results.get('errors')}") | ||
| except Exception as e: | ||
| print(f"Error in retention policy check: {e}") | ||
| # Check every hour | ||
| time.sleep(3600) | ||
paullizer marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| # Start the retention policy check thread | ||
| retention_thread = threading.Thread(target=check_retention_policy, daemon=True) | ||
| retention_thread.start() | ||
| print("Retention policy background task started.") | ||
| # Initialize Semantic Kernel and plugins | ||
| enable_semantic_kernel = settings.get('enable_semantic_kernel', False) | ||
| per_user_semantic_kernel = settings.get('per_user_semantic_kernel', False) | ||
| @@ -330,6 +443,7 @@ def markdown_filter(text): | ||
| # =================== Default Routes ===================== | ||
| @app.route('/') | ||
| @swagger_route(security=get_auth_security()) | ||
| def index(): | ||
| settings = get_settings() | ||
| public_settings = sanitize_settings_for_user(settings) | ||
| @@ -343,14 +457,17 @@ def index(): | ||
| return render_template('index.html', app_settings=public_settings, landing_html=landing_html) | ||
| @app.route('/robots933456.txt') | ||
| @swagger_route(security=get_auth_security()) | ||
| def robots(): | ||
| return send_from_directory('static', 'robots.txt') | ||
| @app.route('/favicon.ico') | ||
| @swagger_route(security=get_auth_security()) | ||
| def favicon(): | ||
| return send_from_directory('static', 'favicon.ico') | ||
| @app.route('/static/js/<path:filename>') | ||
| @swagger_route(security=get_auth_security()) | ||
| def serve_js_modules(filename): | ||
| """Serve JavaScript modules with correct MIME type.""" | ||
| from flask import send_from_directory, Response | ||
| @@ -363,10 +480,12 @@ def serve_js_modules(filename): | ||
| return send_from_directory('static/js', filename) | ||
| @app.route('/acceptable_use_policy.html') | ||
| @swagger_route(security=get_auth_security()) | ||
| def acceptable_use_policy(): | ||
| return render_template('acceptable_use_policy.html') | ||
| @app.route('/api/semantic-kernel/plugins') | ||
| @swagger_route(security=get_auth_security()) | ||
| def list_semantic_kernel_plugins(): | ||
| """Test endpoint: List loaded Semantic Kernel plugins and their functions.""" | ||
| global kernel | ||
| @@ -413,6 +532,9 @@ def list_semantic_kernel_plugins(): | ||
| # ------------------- Feedback Routes ------------------- | ||
| register_route_frontend_feedback(app) | ||
| # ------------------- Notifications Routes -------------- | ||
| register_route_frontend_notifications(app) | ||
| # ------------------- API Chat Routes -------------------- | ||
| register_route_backend_chats(app) | ||
| @@ -452,6 +574,12 @@ def list_semantic_kernel_plugins(): | ||
| # ------------------- API Control Center Routes --------- | ||
| register_route_backend_control_center(app) | ||
| # ------------------- API Notifications Routes ---------- | ||
| register_route_backend_notifications(app) | ||
| # ------------------- API Retention Policy Routes -------- | ||
| register_route_backend_retention_policy(app) | ||
| # ------------------- API Public Workspaces Routes ------- | ||
| register_route_backend_public_workspaces(app) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.