refactored features phase II
This commit is contained in:
parent
bb9630d6c4
commit
280cafd54a
179 changed files with 5422 additions and 1098 deletions
3
app.py
3
app.py
|
|
@ -485,6 +485,9 @@ app.include_router(rbacAdminExportRouter)
|
|||
from modules.routes.routeGdpr import router as gdprRouter
|
||||
app.include_router(gdprRouter)
|
||||
|
||||
from modules.routes.routeChat import router as chatRouter
|
||||
app.include_router(chatRouter)
|
||||
|
||||
# ============================================================================
|
||||
# PLUG&PLAY FEATURE ROUTERS
|
||||
# Dynamically load routers from feature containers in modules/features/
|
||||
|
|
|
|||
|
|
@ -298,7 +298,6 @@ class AiOpenai(BaseConnectorAi):
|
|||
promptContent = messages[0]["content"] if messages else ""
|
||||
|
||||
# Parse prompt using AiCallPromptImage model
|
||||
from modules.datamodels.datamodelAi import AiCallPromptImage
|
||||
import json
|
||||
|
||||
try:
|
||||
|
|
@ -184,7 +184,6 @@ class AiPerplexity(BaseConnectorAi):
|
|||
]
|
||||
|
||||
# Create a model call for testing
|
||||
from modules.datamodels.datamodelAi import AiCallOptions
|
||||
model = self.getModels()[0] # Get first model for testing
|
||||
testCall = AiModelCall(
|
||||
messages=testMessages,
|
||||
|
|
@ -1022,40 +1022,3 @@ registerModelLabels(
|
|||
"placeholders": {"en": "Placeholders", "fr": "Espaces réservés"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class AutomationDefinition(BaseModel):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
mandateId: str = Field(description="Mandate ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
featureInstanceId: str = Field(description="ID of the feature instance this automation belongs to", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
label: str = Field(description="User-friendly name", json_schema_extra={"frontend_type": "text", "frontend_required": True})
|
||||
schedule: str = Field(description="Cron schedule pattern", json_schema_extra={"frontend_type": "select", "frontend_required": True, "frontend_options": [
|
||||
{"value": "0 */4 * * *", "label": {"en": "Every 4 hours", "fr": "Toutes les 4 heures"}},
|
||||
{"value": "0 22 * * *", "label": {"en": "Daily at 22:00", "fr": "Quotidien à 22:00"}},
|
||||
{"value": "0 10 * * 1", "label": {"en": "Weekly Monday 10:00", "fr": "Hebdomadaire lundi 10:00"}}
|
||||
]})
|
||||
template: str = Field(description="JSON template with placeholders (format: {{KEY:PLACEHOLDER_NAME}})", json_schema_extra={"frontend_type": "textarea", "frontend_required": True})
|
||||
placeholders: Dict[str, str] = Field(default_factory=dict, description="Dictionary of placeholder key/value pairs (e.g., {'connectionName': 'MyConnection', 'sharepointFolderNameSource': '/folder/path', 'webResearchUrl': 'https://...', 'webResearchPrompt': '...', 'documentPrompt': '...'})", json_schema_extra={"frontend_type": "text"})
|
||||
active: bool = Field(default=False, description="Whether automation should be launched in event handler", json_schema_extra={"frontend_type": "checkbox", "frontend_required": False})
|
||||
eventId: Optional[str] = Field(None, description="Event ID from event management (None if not registered)", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
status: Optional[str] = Field(None, description="Status: 'active' if event is registered, 'inactive' if not (computed, readonly)", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
executionLogs: List[Dict[str, Any]] = Field(default_factory=list, description="List of execution logs, each containing timestamp, workflowId, status, and messages", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
|
||||
|
||||
registerModelLabels(
|
||||
"AutomationDefinition",
|
||||
{"en": "Automation Definition", "fr": "Définition d'automatisation"},
|
||||
{
|
||||
"id": {"en": "ID", "fr": "ID"},
|
||||
"mandateId": {"en": "Mandate ID", "fr": "ID du mandat"},
|
||||
"featureInstanceId": {"en": "Feature Instance ID", "fr": "ID de l'instance de fonctionnalité"},
|
||||
"label": {"en": "Label", "fr": "Libellé"},
|
||||
"schedule": {"en": "Schedule", "fr": "Planification"},
|
||||
"template": {"en": "Template", "fr": "Modèle"},
|
||||
"placeholders": {"en": "Placeholders", "fr": "Espaces réservés"},
|
||||
"active": {"en": "Active", "fr": "Actif"},
|
||||
"eventId": {"en": "Event ID", "fr": "ID de l'événement"},
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"executionLogs": {"en": "Execution Logs", "fr": "Journaux d'exécution"},
|
||||
},
|
||||
)
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
from typing import Optional, Any, Union, List, Dict, Callable, Awaitable
|
||||
from pydantic import BaseModel, Field
|
||||
from modules.aichat.datamodelFeatureAiChat import ActionResult
|
||||
from modules.datamodels.datamodelChat import ActionResult
|
||||
from modules.shared.frontendTypes import FrontendType
|
||||
from modules.shared.attributeUtils import registerModelLabels
|
||||
|
||||
|
|
|
|||
45
modules/features/automation/datamodelFeatureAutomation.py
Normal file
45
modules/features/automation/datamodelFeatureAutomation.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Copyright (c) 2025 Patrick Motsch
|
||||
# All rights reserved.
|
||||
"""Automation models: AutomationDefinition."""
|
||||
|
||||
from typing import List, Dict, Any, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from modules.shared.attributeUtils import registerModelLabels
|
||||
import uuid
|
||||
|
||||
|
||||
class AutomationDefinition(BaseModel):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
mandateId: str = Field(description="Mandate ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
featureInstanceId: str = Field(description="ID of the feature instance this automation belongs to", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
label: str = Field(description="User-friendly name", json_schema_extra={"frontend_type": "text", "frontend_required": True})
|
||||
schedule: str = Field(description="Cron schedule pattern", json_schema_extra={"frontend_type": "select", "frontend_required": True, "frontend_options": [
|
||||
{"value": "0 */4 * * *", "label": {"en": "Every 4 hours", "fr": "Toutes les 4 heures"}},
|
||||
{"value": "0 22 * * *", "label": {"en": "Daily at 22:00", "fr": "Quotidien à 22:00"}},
|
||||
{"value": "0 10 * * 1", "label": {"en": "Weekly Monday 10:00", "fr": "Hebdomadaire lundi 10:00"}}
|
||||
]})
|
||||
template: str = Field(description="JSON template with placeholders (format: {{KEY:PLACEHOLDER_NAME}})", json_schema_extra={"frontend_type": "textarea", "frontend_required": True})
|
||||
placeholders: Dict[str, str] = Field(default_factory=dict, description="Dictionary of placeholder key/value pairs (e.g., {'connectionName': 'MyConnection', 'sharepointFolderNameSource': '/folder/path', 'webResearchUrl': 'https://...', 'webResearchPrompt': '...', 'documentPrompt': '...'})", json_schema_extra={"frontend_type": "text"})
|
||||
active: bool = Field(default=False, description="Whether automation should be launched in event handler", json_schema_extra={"frontend_type": "checkbox", "frontend_required": False})
|
||||
eventId: Optional[str] = Field(None, description="Event ID from event management (None if not registered)", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
status: Optional[str] = Field(None, description="Status: 'active' if event is registered, 'inactive' if not (computed, readonly)", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
executionLogs: List[Dict[str, Any]] = Field(default_factory=list, description="List of execution logs, each containing timestamp, workflowId, status, and messages", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
|
||||
|
||||
registerModelLabels(
|
||||
"AutomationDefinition",
|
||||
{"en": "Automation Definition", "fr": "Définition d'automatisation"},
|
||||
{
|
||||
"id": {"en": "ID", "fr": "ID"},
|
||||
"mandateId": {"en": "Mandate ID", "fr": "ID du mandat"},
|
||||
"featureInstanceId": {"en": "Feature Instance ID", "fr": "ID de l'instance de fonctionnalité"},
|
||||
"label": {"en": "Label", "fr": "Libellé"},
|
||||
"schedule": {"en": "Schedule", "fr": "Planification"},
|
||||
"template": {"en": "Template", "fr": "Modèle"},
|
||||
"placeholders": {"en": "Placeholders", "fr": "Espaces réservés"},
|
||||
"active": {"en": "Active", "fr": "Actif"},
|
||||
"eventId": {"en": "Event ID", "fr": "ID de l'événement"},
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"executionLogs": {"en": "Execution Logs", "fr": "Journaux d'exécution"},
|
||||
},
|
||||
)
|
||||
|
|
@ -13,9 +13,10 @@ import logging
|
|||
import json
|
||||
|
||||
# Import interfaces and models
|
||||
from modules.aichat.interfaceFeatureAiChat import getInterface as getChatInterface
|
||||
from modules.interfaces.interfaceDbChat import getInterface as getChatInterface
|
||||
from modules.auth import getCurrentUser, limiter
|
||||
from modules.aichat.datamodelFeatureAiChat import AutomationDefinition, ChatWorkflow
|
||||
from modules.features.automation.datamodelFeatureAutomation import AutomationDefinition
|
||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||
from modules.datamodels.datamodelPagination import PaginationParams, PaginatedResponse, PaginationMetadata, normalize_pagination_dict
|
||||
from modules.shared.attributeUtils import getModelAttributeDefinitions
|
||||
from modules.workflows.automation import executeAutomation
|
||||
|
|
|
|||
|
|
@ -1022,40 +1022,3 @@ registerModelLabels(
|
|||
"placeholders": {"en": "Placeholders", "fr": "Espaces réservés"},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class AutomationDefinition(BaseModel):
|
||||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
mandateId: str = Field(description="Mandate ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
featureInstanceId: str = Field(description="ID of the feature instance this automation belongs to", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
label: str = Field(description="User-friendly name", json_schema_extra={"frontend_type": "text", "frontend_required": True})
|
||||
schedule: str = Field(description="Cron schedule pattern", json_schema_extra={"frontend_type": "select", "frontend_required": True, "frontend_options": [
|
||||
{"value": "0 */4 * * *", "label": {"en": "Every 4 hours", "fr": "Toutes les 4 heures"}},
|
||||
{"value": "0 22 * * *", "label": {"en": "Daily at 22:00", "fr": "Quotidien à 22:00"}},
|
||||
{"value": "0 10 * * 1", "label": {"en": "Weekly Monday 10:00", "fr": "Hebdomadaire lundi 10:00"}}
|
||||
]})
|
||||
template: str = Field(description="JSON template with placeholders (format: {{KEY:PLACEHOLDER_NAME}})", json_schema_extra={"frontend_type": "textarea", "frontend_required": True})
|
||||
placeholders: Dict[str, str] = Field(default_factory=dict, description="Dictionary of placeholder key/value pairs (e.g., {'connectionName': 'MyConnection', 'sharepointFolderNameSource': '/folder/path', 'webResearchUrl': 'https://...', 'webResearchPrompt': '...', 'documentPrompt': '...'})", json_schema_extra={"frontend_type": "text"})
|
||||
active: bool = Field(default=False, description="Whether automation should be launched in event handler", json_schema_extra={"frontend_type": "checkbox", "frontend_required": False})
|
||||
eventId: Optional[str] = Field(None, description="Event ID from event management (None if not registered)", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
status: Optional[str] = Field(None, description="Status: 'active' if event is registered, 'inactive' if not (computed, readonly)", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
executionLogs: List[Dict[str, Any]] = Field(default_factory=list, description="List of execution logs, each containing timestamp, workflowId, status, and messages", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
|
||||
|
||||
registerModelLabels(
|
||||
"AutomationDefinition",
|
||||
{"en": "Automation Definition", "fr": "Définition d'automatisation"},
|
||||
{
|
||||
"id": {"en": "ID", "fr": "ID"},
|
||||
"mandateId": {"en": "Mandate ID", "fr": "ID du mandat"},
|
||||
"featureInstanceId": {"en": "Feature Instance ID", "fr": "ID de l'instance de fonctionnalité"},
|
||||
"label": {"en": "Label", "fr": "Libellé"},
|
||||
"schedule": {"en": "Schedule", "fr": "Planification"},
|
||||
"template": {"en": "Template", "fr": "Modèle"},
|
||||
"placeholders": {"en": "Placeholders", "fr": "Espaces réservés"},
|
||||
"active": {"en": "Active", "fr": "Actif"},
|
||||
"eventId": {"en": "Event ID", "fr": "ID de l'événement"},
|
||||
"status": {"en": "Status", "fr": "Statut"},
|
||||
"executionLogs": {"en": "Execution Logs", "fr": "Journaux d'exécution"},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ from .datamodelFeatureChatbot import (
|
|||
ChatMessage,
|
||||
ChatWorkflow,
|
||||
WorkflowModeEnum,
|
||||
AutomationDefinition,
|
||||
UserInputRequest
|
||||
)
|
||||
from modules.features.automation.datamodelFeatureAutomation import AutomationDefinition
|
||||
import json
|
||||
from modules.datamodels.datamodelUam import User
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ import asyncio
|
|||
import re
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
from modules.aichat.datamodelFeatureAiChat import ChatWorkflow, UserInputRequest, WorkflowModeEnum, ChatLog, ChatDocument
|
||||
from modules.features.chatbot.datamodelFeatureChatbot import ChatWorkflow, UserInputRequest, WorkflowModeEnum, ChatLog, ChatDocument
|
||||
from modules.datamodels.datamodelUam import User
|
||||
from modules.datamodels.datamodelAi import AiCallRequest, AiCallOptions, OperationTypeEnum, ProcessingModeEnum
|
||||
from modules.datamodels.datamodelDocref import DocumentReferenceList, DocumentItemReference
|
||||
|
|
@ -439,7 +439,6 @@ async def _emit_log_and_event(
|
|||
# Emit event directly for streaming (using correct signature)
|
||||
if created_log and event_manager:
|
||||
try:
|
||||
from modules.aichat.datamodelFeatureAiChat import ChatLog
|
||||
# Convert to dict if it's a Pydantic model
|
||||
if hasattr(created_log, "model_dump"):
|
||||
log_dict = created_log.model_dump()
|
||||
|
|
@ -1248,7 +1247,6 @@ async def _processChatbotMessage(
|
|||
)
|
||||
|
||||
# Retry analysis with empty results context - create NEW analysis with alternative strategies
|
||||
from modules.features.chatbot.chatbotConstants import get_empty_results_retry_instructions
|
||||
|
||||
# Build retry prompt with progressively different strategies
|
||||
empty_count = len(sql_queries)
|
||||
|
|
|
|||
|
|
@ -432,7 +432,6 @@ async def get_chatbot_threads(
|
|||
normalized_workflows.append(normalized_wf)
|
||||
|
||||
# Create paginated response
|
||||
from modules.datamodels.datamodelPagination import PaginationMetadata
|
||||
metadata = PaginationMetadata(
|
||||
currentPage=paginationParams.page if paginationParams else 1,
|
||||
pageSize=paginationParams.pageSize if paginationParams else len(workflows),
|
||||
|
|
|
|||
|
|
@ -182,7 +182,6 @@ class SharepointProcessor:
|
|||
|
||||
async def _getSharepointConnection(self, sharepointPath: str = None):
|
||||
try:
|
||||
from modules.datamodels.datamodelUam import UserConnection
|
||||
connections = self.services.interfaceDbApp.db.getRecordset(
|
||||
UserConnection,
|
||||
recordFilter={"userId": self.services.interfaceDbApp.userId}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import time
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from modules.aichat.aicore.aicoreModelRegistry import modelRegistry
|
||||
from modules.aichat.aicore.aicoreModelSelector import modelSelector
|
||||
from modules.aicore.aicoreModelRegistry import modelRegistry
|
||||
from modules.aicore.aicoreModelSelector import modelSelector
|
||||
from modules.datamodels.datamodelAi import (
|
||||
AiModel,
|
||||
AiCallOptions,
|
||||
|
|
|
|||
|
|
@ -16,16 +16,16 @@ from modules.security.rbac import RbacClass
|
|||
from modules.datamodels.datamodelRbac import AccessRuleContext
|
||||
from modules.datamodels.datamodelUam import AccessLevel
|
||||
|
||||
from .datamodelFeatureAiChat import (
|
||||
from modules.datamodels.datamodelChat import (
|
||||
ChatDocument,
|
||||
ChatStat,
|
||||
ChatLog,
|
||||
ChatMessage,
|
||||
ChatWorkflow,
|
||||
WorkflowModeEnum,
|
||||
AutomationDefinition,
|
||||
UserInputRequest
|
||||
)
|
||||
from modules.features.automation.datamodelFeatureAutomation import AutomationDefinition
|
||||
import json
|
||||
from modules.datamodels.datamodelUam import User
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ from fastapi import status
|
|||
import logging
|
||||
|
||||
# Import interfaces and models from feature containers
|
||||
import modules.aichat.interfaceFeatureAiChat as interfaceDbChat
|
||||
import modules.interfaces.interfaceDbChat as interfaceDbChat
|
||||
from modules.auth import limiter, getRequestContext, requireSysAdmin, RequestContext
|
||||
from modules.datamodels.datamodelUam import User
|
||||
|
||||
|
|
@ -76,7 +76,6 @@ async def sync_all_automation_events(
|
|||
This will register/remove events based on active flags.
|
||||
"""
|
||||
try:
|
||||
from modules.aichat.interfaceFeatureAiChat import getInterface as getChatInterface
|
||||
from modules.interfaces.interfaceDbApp import getRootInterface
|
||||
from modules.workflows.automation import syncAutomationEvents
|
||||
|
||||
|
|
|
|||
|
|
@ -799,7 +799,6 @@ async def listFeatureInstanceUsers(
|
|||
# Get all FeatureAccess records for this instance
|
||||
from modules.datamodels.datamodelMembership import FeatureAccess, FeatureAccessRole
|
||||
from modules.datamodels.datamodelRbac import Role
|
||||
from modules.datamodels.datamodelUam import UserInDB
|
||||
|
||||
featureAccesses = rootInterface.db.getRecordset(
|
||||
FeatureAccess,
|
||||
|
|
@ -899,7 +898,6 @@ async def addUserToFeatureInstance(
|
|||
)
|
||||
|
||||
# Verify user exists
|
||||
from modules.datamodels.datamodelUam import UserInDB
|
||||
users = rootInterface.db.getRecordset(UserInDB, recordFilter={"id": data.userId})
|
||||
if not users:
|
||||
raise HTTPException(
|
||||
|
|
|
|||
|
|
@ -364,7 +364,6 @@ async def listUsersWithRoles(
|
|||
|
||||
# Get all users (SysAdmin sees all)
|
||||
# Use db.getRecordset with UserInDB (the actual database model)
|
||||
from modules.datamodels.datamodelUam import User, UserInDB
|
||||
allUsersData = interface.db.getRecordset(UserInDB)
|
||||
# Convert to User objects, filtering out sensitive fields
|
||||
users = []
|
||||
|
|
@ -376,7 +375,6 @@ async def listUsersWithRoles(
|
|||
|
||||
# Filter by mandate if specified (via UserMandate table)
|
||||
if mandateId:
|
||||
from modules.datamodels.datamodelMembership import UserMandate
|
||||
userMandates = interface.db.getRecordset(UserMandate, recordFilter={"mandateId": mandateId})
|
||||
mandateUserIds = {str(um["userId"]) for um in userMandates}
|
||||
users = [u for u in users if str(u.id) in mandateUserIds]
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ from modules.auth import limiter, getRequestContext, RequestContext
|
|||
from . import interfaceFeatureAiChat as interfaceDbChat
|
||||
|
||||
# Import models
|
||||
from .datamodelFeatureAiChat import ChatWorkflow, UserInputRequest, WorkflowModeEnum
|
||||
from modules.datamodels.datamodelChat import ChatWorkflow, UserInputRequest, WorkflowModeEnum
|
||||
|
||||
# Import workflow control functions
|
||||
from modules.workflows.automation import chatStart, chatStop
|
||||
|
|
@ -182,7 +182,6 @@ async def get_connections(
|
|||
|
||||
# Perform silent token refresh for expired OAuth connections
|
||||
try:
|
||||
from modules.auth import token_refresh_service
|
||||
refresh_result = await token_refresh_service.refresh_expired_tokens(currentUser.id)
|
||||
if refresh_result.get("refreshed", 0) > 0:
|
||||
logger.info(f"Silently refreshed {refresh_result['refreshed']} tokens for user {currentUser.id}")
|
||||
|
|
|
|||
|
|
@ -291,7 +291,6 @@ async def delete_mandate(
|
|||
)
|
||||
|
||||
# MULTI-TENANT: Delete all UserMandate entries for this mandate first
|
||||
from modules.datamodels.datamodelMembership import UserMandate
|
||||
userMandates = appInterface.db.getRecordset(UserMandate, recordFilter={"mandateId": mandateId})
|
||||
for um in userMandates:
|
||||
appInterface.db.deleteRecord(UserMandate, um["id"])
|
||||
|
|
|
|||
|
|
@ -252,7 +252,6 @@ async def get_users(
|
|||
elif context.isSysAdmin:
|
||||
# SysAdmin without mandateId sees all users
|
||||
# Get all users directly from database using UserInDB (the actual database model)
|
||||
from modules.datamodels.datamodelUam import UserInDB
|
||||
allUsers = appInterface.db.getRecordset(UserInDB)
|
||||
# Convert to cleaned dictionaries first for filtering
|
||||
cleanedUsers = []
|
||||
|
|
@ -378,7 +377,6 @@ async def create_user(
|
|||
appInterface = interfaceDbApp.getInterface(context.user)
|
||||
|
||||
# Extract fields from request model and call createUser with individual parameters
|
||||
from modules.datamodels.datamodelUam import AuthAuthority
|
||||
newUser = appInterface.createUser(
|
||||
username=userData.username,
|
||||
password=userData.password,
|
||||
|
|
@ -512,7 +510,6 @@ async def reset_user_password(
|
|||
|
||||
# SECURITY: Automatically revoke all tokens for the user after password reset
|
||||
try:
|
||||
from modules.datamodels.datamodelUam import AuthAuthority
|
||||
revoked_count = appInterface.revokeTokensByUser(
|
||||
userId=userId,
|
||||
authority=None, # Revoke all authorities
|
||||
|
|
@ -593,7 +590,6 @@ async def change_password(
|
|||
|
||||
# SECURITY: Automatically revoke all tokens for the user after password change
|
||||
try:
|
||||
from modules.datamodels.datamodelUam import AuthAuthority
|
||||
revoked_count = appInterface.revokeTokensByUser(
|
||||
userId=str(context.user.id),
|
||||
authority=None, # Revoke all authorities
|
||||
|
|
@ -654,7 +650,6 @@ async def sendPasswordLink(
|
|||
"""
|
||||
try:
|
||||
from modules.shared.configuration import APP_CONFIG
|
||||
from modules.interfaces.interfaceDbApp import getRootInterface
|
||||
|
||||
# Get user interface
|
||||
appInterface = interfaceDbApp.getInterface(context.user)
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ from fastapi import APIRouter, HTTPException, Depends, Body, Path, Query, Respon
|
|||
from modules.auth import limiter, getCurrentUser
|
||||
|
||||
# Import interfaces from feature containers
|
||||
import modules.aichat.interfaceFeatureAiChat as interfaceDbChat
|
||||
from modules.aichat.interfaceFeatureAiChat import getInterface
|
||||
import modules.interfaces.interfaceDbChat as interfaceDbChat
|
||||
from modules.interfaces.interfaceDbChat import getInterface
|
||||
from modules.interfaces.interfaceRbac import getRecordsetWithRBAC
|
||||
|
||||
# Import models from feature containers
|
||||
from modules.aichat.datamodelFeatureAiChat import (
|
||||
from modules.datamodels.datamodelChat import (
|
||||
ChatWorkflow,
|
||||
ChatMessage,
|
||||
ChatLog,
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ async def exportUserData(
|
|||
mandateId = um.get("mandateId")
|
||||
|
||||
# Get mandate details
|
||||
from modules.datamodels.datamodelUam import Mandate
|
||||
mandateRecords = rootInterface.db.getRecordset(
|
||||
Mandate,
|
||||
recordFilter={"id": mandateId}
|
||||
|
|
@ -278,7 +277,6 @@ async def exportPortableData(
|
|||
|
||||
affiliations = []
|
||||
for um in userMandates:
|
||||
from modules.datamodels.datamodelUam import Mandate
|
||||
mandateRecords = rootInterface.db.getRecordset(
|
||||
Mandate,
|
||||
recordFilter={"id": um.get("mandateId")}
|
||||
|
|
@ -418,7 +416,6 @@ async def deleteAccount(
|
|||
deletedData.append(f"Tokens deleted: {len(userTokens)}")
|
||||
|
||||
# 5. Delete user connections (OAuth)
|
||||
from modules.datamodels.datamodelUam import UserConnection
|
||||
userConnections = rootInterface.db.getRecordset(
|
||||
UserConnection,
|
||||
recordFilter={"userId": str(currentUser.id)}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,6 @@ async def login(
|
|||
try:
|
||||
if connectionId:
|
||||
rootInterface = getRootInterface()
|
||||
from modules.datamodels.datamodelUam import UserConnection
|
||||
records = rootInterface.db.getRecordset(UserConnection, recordFilter={"id": connectionId})
|
||||
if records:
|
||||
record = records[0]
|
||||
|
|
@ -356,7 +355,6 @@ async def auth_callback(code: str, state: str, request: Request, response: Respo
|
|||
|
||||
# Decode token to get jti for database record
|
||||
from jose import jwt
|
||||
from modules.auth import SECRET_KEY, ALGORITHM
|
||||
payload = jwt.decode(jwt_token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||
jti = payload.get("jti")
|
||||
|
||||
|
|
@ -494,7 +492,6 @@ async def auth_callback(code: str, state: str, request: Request, response: Respo
|
|||
connection.externalEmail = user_info.get("email")
|
||||
|
||||
# Update connection record directly
|
||||
from modules.datamodels.datamodelUam import UserConnection
|
||||
rootInterface.db.recordModify(UserConnection, connection_id, connection.model_dump())
|
||||
|
||||
|
||||
|
|
@ -667,7 +664,6 @@ async def verify_token(
|
|||
)
|
||||
|
||||
# Get a fresh token via TokenManager convenience method
|
||||
from modules.auth import TokenManager
|
||||
current_token = TokenManager().getFreshToken(google_connection.id)
|
||||
|
||||
if not current_token:
|
||||
|
|
@ -741,7 +737,6 @@ async def refresh_token(
|
|||
logger.debug(f"Found Google connection: {google_connection.id}, status={google_connection.status}")
|
||||
|
||||
# Get the token for this specific connection (fresh if expiring soon)
|
||||
from modules.auth import TokenManager
|
||||
current_token = TokenManager().getFreshToken(google_connection.id)
|
||||
|
||||
if not current_token:
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@ async def login(
|
|||
rootInterface = getRootInterface()
|
||||
|
||||
# Get default mandate ID
|
||||
from modules.datamodels.datamodelUam import Mandate
|
||||
defaultMandateId = rootInterface.getInitialId(Mandate)
|
||||
if not defaultMandateId:
|
||||
raise HTTPException(
|
||||
|
|
@ -267,7 +266,6 @@ async def register_user(
|
|||
appInterface = getRootInterface()
|
||||
|
||||
# Get default mandate ID
|
||||
from modules.datamodels.datamodelUam import Mandate
|
||||
defaultMandateId = appInterface.getInitialId(Mandate)
|
||||
if not defaultMandateId:
|
||||
raise HTTPException(
|
||||
|
|
|
|||
|
|
@ -364,7 +364,6 @@ async def auth_callback(code: str, state: str, request: Request, response: Respo
|
|||
|
||||
# Decode token to get jti for database record
|
||||
from jose import jwt
|
||||
from modules.auth import SECRET_KEY, ALGORITHM
|
||||
payload = jwt.decode(jwt_token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||
jti = payload.get("jti")
|
||||
|
||||
|
|
@ -726,7 +725,6 @@ async def refresh_token(
|
|||
logger.debug(f"Found Microsoft connection: {msft_connection.id}, status={msft_connection.status}")
|
||||
|
||||
# Get a fresh token via TokenManager convenience method
|
||||
from modules.auth import TokenManager
|
||||
current_token = TokenManager().getFreshToken(msft_connection.id)
|
||||
|
||||
if not current_token:
|
||||
|
|
@ -738,7 +736,6 @@ async def refresh_token(
|
|||
|
||||
|
||||
# Always attempt refresh (as per your requirement)
|
||||
from modules.auth import TokenManager
|
||||
token_manager = TokenManager()
|
||||
|
||||
refreshedToken = token_manager.refreshToken(current_token)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import logging
|
|||
from modules.datamodels.datamodelUam import User
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from modules.aichat.datamodelFeatureAiChat import ChatWorkflow
|
||||
from modules.datamodels.datamodelChat import ChatWorkflow
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -79,6 +79,12 @@ class Services:
|
|||
|
||||
self.rbac = self.interfaceDbApp.rbac if self.interfaceDbApp else None
|
||||
|
||||
# ============================================================
|
||||
# CENTRAL INTERFACE (Chat/Workflow)
|
||||
# ============================================================
|
||||
from modules.interfaces.interfaceDbChat import getInterface as getChatInterface
|
||||
self.interfaceDbChat = getChatInterface(user, mandateId=mandateId)
|
||||
|
||||
# ============================================================
|
||||
# SHARED SERVICES (from modules/services/)
|
||||
# ============================================================
|
||||
|
|
@ -101,7 +107,22 @@ class Services:
|
|||
self.messaging = PublicService(MessagingService(self))
|
||||
|
||||
# ============================================================
|
||||
# FEATURE SERVICES (dynamically loaded by filename discovery)
|
||||
# AI SERVICES (from modules/services/)
|
||||
# ============================================================
|
||||
from .serviceAi.mainServiceAi import AiService
|
||||
self.ai = PublicService(AiService(self), functionsOnly=False)
|
||||
|
||||
from .serviceExtraction.mainServiceExtraction import ExtractionService
|
||||
self.extraction = PublicService(ExtractionService(self))
|
||||
|
||||
from .serviceGeneration.mainServiceGeneration import GenerationService
|
||||
self.generation = PublicService(GenerationService(self))
|
||||
|
||||
from .serviceWeb.mainServiceWeb import WebService
|
||||
self.web = PublicService(WebService(self))
|
||||
|
||||
# ============================================================
|
||||
# FEATURE INTERFACES (dynamically loaded)
|
||||
# ============================================================
|
||||
self._loadFeatureInterfaces()
|
||||
self._loadFeatureServices()
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ async def onStart(eventUser) -> None:
|
|||
Initializes AI connectors for model registry.
|
||||
"""
|
||||
try:
|
||||
from .aicore.aicoreModelRegistry import modelRegistry
|
||||
from modules.aicore.aicoreModelRegistry import modelRegistry
|
||||
modelRegistry.ensureConnectorsRegistered()
|
||||
logger.info(f"Feature '{FEATURE_CODE}' started - AI connectors initialized")
|
||||
except Exception as e:
|
||||
|
|
@ -6,8 +6,8 @@ import re
|
|||
import time
|
||||
import base64
|
||||
from typing import Dict, Any, List, Optional, Tuple
|
||||
from modules.aichat.datamodelFeatureAiChat import PromptPlaceholder, ChatDocument
|
||||
from modules.aichat.serviceExtraction.mainServiceExtraction import ExtractionService
|
||||
from modules.datamodels.datamodelChat import PromptPlaceholder, ChatDocument
|
||||
from modules.services.serviceExtraction.mainServiceExtraction import ExtractionService
|
||||
from modules.datamodels.datamodelAi import AiCallRequest, AiCallOptions, OperationTypeEnum, PriorityEnum, ProcessingModeEnum
|
||||
from modules.datamodels.datamodelExtraction import ContentPart, DocumentIntent
|
||||
from modules.datamodels.datamodelWorkflow import AiResponse, AiResponseMetadata, DocumentData
|
||||
|
|
@ -329,7 +329,7 @@ Respond with ONLY a JSON object in this exact format:
|
|||
parentOperationId: Optional[str]
|
||||
) -> AiResponse:
|
||||
"""Handle IMAGE_GENERATE operation type using image generation path."""
|
||||
from modules.aichat.serviceGeneration.paths.imagePath import ImageGenerationPath
|
||||
from modules.services.serviceGeneration.paths.imagePath import ImageGenerationPath
|
||||
|
||||
imagePath = ImageGenerationPath(self.services)
|
||||
|
||||
|
|
@ -514,7 +514,7 @@ Respond with ONLY a JSON object in this exact format:
|
|||
)
|
||||
|
||||
try:
|
||||
from modules.aichat.serviceGeneration.mainServiceGeneration import GenerationService
|
||||
from modules.services.serviceGeneration.mainServiceGeneration import GenerationService
|
||||
|
||||
generationService = GenerationService(self.services)
|
||||
|
||||
|
|
@ -829,7 +829,7 @@ Respond with ONLY a JSON object in this exact format:
|
|||
parentOperationId: Optional[str]
|
||||
) -> AiResponse:
|
||||
"""Handle code generation using code generation path."""
|
||||
from modules.aichat.serviceGeneration.paths.codePath import CodeGenerationPath
|
||||
from modules.services.serviceGeneration.paths.codePath import CodeGenerationPath
|
||||
|
||||
codePath = CodeGenerationPath(self.services)
|
||||
return await codePath.generateCode(
|
||||
|
|
@ -852,7 +852,7 @@ Respond with ONLY a JSON object in this exact format:
|
|||
parentOperationId: Optional[str]
|
||||
) -> AiResponse:
|
||||
"""Handle document generation using document generation path."""
|
||||
from modules.aichat.serviceGeneration.paths.documentPath import DocumentGenerationPath
|
||||
from modules.services.serviceGeneration.paths.documentPath import DocumentGenerationPath
|
||||
|
||||
# Set compression options for document generation
|
||||
options.compressPrompt = False
|
||||
|
|
@ -14,7 +14,7 @@ import logging
|
|||
import base64
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
from modules.aichat.datamodelFeatureAiChat import ChatDocument
|
||||
from modules.datamodels.datamodelChat import ChatDocument
|
||||
from modules.datamodels.datamodelExtraction import ContentPart, DocumentIntent
|
||||
from modules.workflows.processing.shared.stateTools import checkWorkflowStopped
|
||||
|
||||
|
|
@ -387,7 +387,6 @@ class ContentExtractor:
|
|||
)
|
||||
|
||||
# Führe Extraktion aus
|
||||
from modules.datamodels.datamodelExtraction import ExtractionOptions, MergeStrategy
|
||||
|
||||
extractionOptions = ExtractionOptions(
|
||||
prompt=extractionPrompt,
|
||||
|
|
@ -12,7 +12,7 @@ import json
|
|||
import logging
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
from modules.aichat.datamodelFeatureAiChat import ChatDocument
|
||||
from modules.datamodels.datamodelChat import ChatDocument
|
||||
from modules.datamodels.datamodelExtraction import DocumentIntent
|
||||
from modules.workflows.processing.shared.stateTools import checkWorkflowStopped
|
||||
|
||||
|
|
@ -181,7 +181,6 @@ class DocumentIntentAnalyzer:
|
|||
logger.debug(f"JSON document {document.id} does not have actionType='context.extractContent' (got: {actionType})")
|
||||
|
||||
if documentData:
|
||||
from modules.datamodels.datamodelExtraction import ContentExtracted
|
||||
|
||||
try:
|
||||
# Stelle sicher, dass "id" vorhanden ist
|
||||
|
|
@ -1357,7 +1357,6 @@ class JsonResponseHandler:
|
|||
logger.debug(f"Modular merger failed, using fallback: {e}")
|
||||
|
||||
# Fallback to legacy merger (simplified)
|
||||
from modules.shared.jsonUtils import normalizeJsonText, stripCodeFences, closeJsonStructures, tryParseJson
|
||||
|
||||
accumulatedExtracted = stripCodeFences(normalizeJsonText(accumulated)).strip()
|
||||
newFragmentExtracted = stripCodeFences(normalizeJsonText(newFragment)).strip()
|
||||
|
|
@ -1450,7 +1449,6 @@ class JsonResponseHandler:
|
|||
if not jsonString:
|
||||
return None
|
||||
|
||||
from modules.shared.jsonUtils import tryParseJson, repairBrokenJson, closeJsonStructures
|
||||
|
||||
# Try to parse directly first
|
||||
try:
|
||||
|
|
@ -1535,7 +1533,6 @@ class JsonResponseHandler:
|
|||
# Strategy 1: Check if it's an array fragment
|
||||
if jsonStripped.startswith('['):
|
||||
# Try to parse as array
|
||||
from modules.shared.jsonUtils import tryParseJson, closeJsonStructures
|
||||
|
||||
# Close incomplete structures
|
||||
closed = closeJsonStructures(jsonStripped)
|
||||
|
|
@ -1579,7 +1576,6 @@ class JsonResponseHandler:
|
|||
# Strategy 2: Check if it's a partial object (cut mid-structure)
|
||||
# Look for patterns like: {"elements": [...] or {"type": "table"...
|
||||
if jsonStripped.startswith('{'):
|
||||
from modules.shared.jsonUtils import tryParseJson, closeJsonStructures
|
||||
|
||||
# Try to close and parse
|
||||
closed = closeJsonStructures(jsonStripped)
|
||||
|
|
@ -1690,7 +1686,6 @@ class JsonResponseHandler:
|
|||
if not accumulatedElements and not newFragmentElements:
|
||||
# No elements found - try to extract from raw strings
|
||||
# Try to extract any valid JSON structure from raw strings
|
||||
from modules.shared.jsonUtils import tryParseJson, closeJsonStructures
|
||||
|
||||
# Try accumulated first
|
||||
if accumulatedRaw:
|
||||
|
|
@ -2019,7 +2014,6 @@ class JsonResponseHandler:
|
|||
return rows
|
||||
|
||||
# Pattern 4: Try to parse as JSON array (handles complete arrays)
|
||||
from modules.shared.jsonUtils import tryParseJson, closeJsonStructures
|
||||
|
||||
# Try to close incomplete structures
|
||||
closed = closeJsonStructures(fragmentRaw.strip())
|
||||
|
|
@ -2292,7 +2286,6 @@ class JsonResponseHandler:
|
|||
if not jsonString:
|
||||
return None, None
|
||||
|
||||
from modules.shared.jsonUtils import stripCodeFences, normalizeJsonText, tryParseJson, closeJsonStructures
|
||||
|
||||
# Extract and normalize JSON
|
||||
extracted = stripCodeFences(normalizeJsonText(jsonString)).strip()
|
||||
|
|
@ -2366,7 +2359,6 @@ class JsonResponseHandler:
|
|||
if not continuationJson:
|
||||
return accumulated
|
||||
|
||||
from modules.shared.jsonUtils import stripCodeFences, normalizeJsonText, tryParseJson, closeJsonStructures
|
||||
|
||||
# Normalize accumulated
|
||||
accumulatedExtracted = stripCodeFences(normalizeJsonText(accumulated)).strip()
|
||||
|
|
@ -2429,7 +2421,6 @@ class JsonResponseHandler:
|
|||
if not jsonString or not jsonString.strip():
|
||||
return ""
|
||||
|
||||
from modules.shared.jsonUtils import tryParseJson, closeJsonStructures
|
||||
|
||||
# Strategy 1: Try progressive truncation to find longest valid JSON
|
||||
# Use binary search-like approach for efficiency
|
||||
|
|
@ -2484,7 +2475,6 @@ class JsonResponseHandler:
|
|||
|
||||
if jsonStripped.startswith('{') or jsonStripped.startswith('['):
|
||||
# Try to extract balanced JSON
|
||||
from modules.shared.jsonUtils import extractFirstBalancedJson
|
||||
balanced = extractFirstBalancedJson(jsonStripped)
|
||||
if balanced and balanced != jsonStripped:
|
||||
try:
|
||||
|
|
@ -2554,7 +2544,6 @@ class JsonResponseHandler:
|
|||
if not accumulated or not newFragment:
|
||||
return ""
|
||||
|
||||
from modules.shared.jsonUtils import closeJsonStructures, tryParseJson
|
||||
|
||||
# Extract valid JSON prefixes from both
|
||||
accumulatedValid = JsonResponseHandler._extractValidJsonPrefix(accumulated)
|
||||
|
|
@ -2647,7 +2636,6 @@ class JsonResponseHandler:
|
|||
if not newFragment:
|
||||
return accumulated
|
||||
|
||||
from modules.shared.jsonUtils import tryParseJson, closeJsonStructures
|
||||
|
||||
# Strategy 1: Try to extract valid JSON parts from both fragments
|
||||
# This handles random cuts better by finding the longest valid prefix/suffix
|
||||
|
|
@ -2894,7 +2882,6 @@ class JsonResponseHandler:
|
|||
|
||||
try:
|
||||
# Use existing JSON completion function to close incomplete structures
|
||||
from modules.shared.jsonUtils import extractJsonString, closeJsonStructures
|
||||
|
||||
# Extract JSON string and complete it with missing closing elements
|
||||
extracted = extractJsonString(jsonString)
|
||||
|
|
@ -2531,7 +2531,7 @@ CRITICAL:
|
|||
List of accepted section content types (e.g., ["table", "code_block"])
|
||||
"""
|
||||
try:
|
||||
from modules.aichat.serviceGeneration.renderers.registry import getRenderer
|
||||
from modules.services.serviceGeneration.renderers.registry import getRenderer
|
||||
|
||||
# Get renderer for this format
|
||||
renderer = getRenderer(outputFormat, self.services)
|
||||
|
|
@ -231,7 +231,7 @@ CRITICAL:
|
|||
raise ValueError("Structure has no documents - cannot generate without documents")
|
||||
|
||||
# Import renderer registry for format validation (existing infrastructure)
|
||||
from modules.aichat.serviceGeneration.renderers.registry import getRenderer
|
||||
from modules.services.serviceGeneration.renderers.registry import getRenderer
|
||||
|
||||
# Validate and fix each document
|
||||
for doc in documents:
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
import logging
|
||||
from typing import Dict, Any, List, Optional
|
||||
from modules.datamodels.datamodelUam import User, UserConnection
|
||||
from modules.aichat.datamodelFeatureAiChat import ChatDocument, ChatMessage, ChatStat, ChatLog
|
||||
from modules.datamodels.datamodelChat import ChatDocument, ChatMessage, ChatStat, ChatLog
|
||||
from modules.datamodels.datamodelAi import AiCallOptions, OperationTypeEnum, PriorityEnum, ProcessingModeEnum
|
||||
from modules.shared.progressLogger import ProgressLogger
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ import json
|
|||
from .subRegistry import ExtractorRegistry, ChunkerRegistry
|
||||
from .subPipeline import runExtraction
|
||||
from modules.datamodels.datamodelExtraction import ContentExtracted, ContentPart, MergeStrategy, ExtractionOptions, PartResult, DocumentIntent
|
||||
from modules.aichat.datamodelFeatureAiChat import ChatDocument
|
||||
from modules.datamodels.datamodelChat import ChatDocument
|
||||
from modules.datamodels.datamodelAi import AiCallResponse, AiCallRequest, AiCallOptions, OperationTypeEnum, AiModelCall
|
||||
from modules.aichat.aicore.aicoreModelRegistry import modelRegistry
|
||||
from modules.aichat.aicore.aicoreModelSelector import modelSelector
|
||||
from modules.aicore.aicoreModelRegistry import modelRegistry
|
||||
from modules.aicore.aicoreModelSelector import modelSelector
|
||||
from modules.shared.jsonUtils import stripCodeFences
|
||||
|
||||
|
||||
|
|
@ -692,7 +692,6 @@ class ExtractionService:
|
|||
isGenerationResponse = False
|
||||
if options and hasattr(options, 'operationType'):
|
||||
# Generation responses use DATA_GENERATE operation type
|
||||
from modules.datamodels.datamodelAi import OperationTypeEnum
|
||||
isGenerationResponse = options.operationType == OperationTypeEnum.DATA_GENERATE
|
||||
|
||||
# Also check if content looks like JSON (starts with { or [)
|
||||
|
|
@ -13,7 +13,7 @@ from modules.datamodels.datamodelAi import AiCallRequest, AiCallOptions, Operati
|
|||
# Type hint for renderer parameter
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from modules.aichat.serviceGeneration.renderers.documentRendererBaseTemplate import BaseRenderer
|
||||
from modules.services.serviceGeneration.renderers.documentRendererBaseTemplate import BaseRenderer
|
||||
_RendererLike = BaseRenderer
|
||||
else:
|
||||
_RendererLike = Any
|
||||
|
|
@ -71,7 +71,7 @@ class ExtractorRegistry:
|
|||
module_name = file_path.stem
|
||||
try:
|
||||
# Import the module
|
||||
module = importlib.import_module(f".{module_name}", package="modules.aichat.serviceExtraction.extractors")
|
||||
module = importlib.import_module(f".{module_name}", package="modules.services.serviceExtraction.extractors")
|
||||
|
||||
# Find all extractor classes in the module
|
||||
for attr_name in dir(module):
|
||||
|
|
@ -6,8 +6,8 @@ import base64
|
|||
import traceback
|
||||
from typing import Any, Dict, List, Optional, Callable
|
||||
from modules.datamodels.datamodelDocument import RenderedDocument
|
||||
from modules.aichat.datamodelFeatureAiChat import ChatDocument
|
||||
from modules.aichat.serviceGeneration.subDocumentUtility import (
|
||||
from modules.datamodels.datamodelChat import ChatDocument
|
||||
from modules.services.serviceGeneration.subDocumentUtility import (
|
||||
getFileExtension,
|
||||
getMimeTypeFromExtension,
|
||||
detectMimeTypeFromContent,
|
||||
|
|
@ -414,7 +414,7 @@ class GenerationService:
|
|||
continue
|
||||
|
||||
# Check output style classification (code/document/image/etc.) from renderer
|
||||
from modules.aichat.serviceGeneration.renderers.registry import getOutputStyle
|
||||
from modules.services.serviceGeneration.renderers.registry import getOutputStyle
|
||||
outputStyle = getOutputStyle(docFormat)
|
||||
if outputStyle:
|
||||
logger.debug(f"Document {doc.get('id', docIndex)} format '{docFormat}' classified as '{outputStyle}' style")
|
||||
|
|
@ -471,8 +471,8 @@ class GenerationService:
|
|||
Complete document structure with populated elements ready for rendering
|
||||
"""
|
||||
try:
|
||||
from modules.aichat.serviceGeneration.subStructureGenerator import StructureGenerator
|
||||
from modules.aichat.serviceGeneration.subContentGenerator import ContentGenerator
|
||||
from modules.services.serviceGeneration.subStructureGenerator import StructureGenerator
|
||||
from modules.services.serviceGeneration.subContentGenerator import ContentGenerator
|
||||
|
||||
# Phase 1: Generate structure skeleton
|
||||
if progressCallback:
|
||||
|
|
@ -537,7 +537,7 @@ class GenerationService:
|
|||
aiService=None
|
||||
) -> str:
|
||||
"""Get adaptive extraction prompt."""
|
||||
from modules.aichat.serviceExtraction.subPromptBuilderExtraction import buildExtractionPrompt
|
||||
from modules.services.serviceExtraction.subPromptBuilderExtraction import buildExtractionPrompt
|
||||
return await buildExtractionPrompt(
|
||||
outputFormat=outputFormat,
|
||||
userPrompt=userPrompt,
|
||||
|
|
@ -920,7 +920,7 @@ CRITICAL:
|
|||
|
||||
def _getCodeRenderer(self, fileType: str):
|
||||
"""Get code renderer for file type."""
|
||||
from modules.aichat.serviceGeneration.renderers.registry import getRenderer
|
||||
from modules.services.serviceGeneration.renderers.registry import getRenderer
|
||||
|
||||
# Map file types to renderer formats
|
||||
formatMap = {
|
||||
|
|
@ -81,7 +81,6 @@ class BaseRenderer(ABC):
|
|||
Valid types: "table", "bullet_list", "heading", "paragraph", "code_block", "image"
|
||||
"""
|
||||
# Default: accept all section types
|
||||
from modules.datamodels.datamodelJson import supportedSectionTypes
|
||||
return list(supportedSectionTypes)
|
||||
|
||||
@abstractmethod
|
||||
|
|
@ -12,7 +12,7 @@ import base64
|
|||
import re
|
||||
import traceback
|
||||
from typing import Dict, Any, Optional, List, Callable
|
||||
from modules.aichat.serviceGeneration.subContentIntegrator import ContentIntegrator
|
||||
from modules.services.serviceGeneration.subContentIntegrator import ContentIntegrator
|
||||
from modules.workflows.processing.shared.stateTools import checkWorkflowStopped
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue