ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: интерактивный предпросмотр Voice Tasker
This commit is contained in:
@@ -691,6 +691,8 @@ def harden_voice_task_intent(parsed, transcript):
|
||||
|
||||
if parsed.get("intent") != "update_task":
|
||||
return parsed
|
||||
if parsed.get("target_task_id"):
|
||||
return parsed
|
||||
|
||||
target_memory_ref = normalize_string(parsed.get("target_memory_ref"), 80)
|
||||
has_explicit_issue_ref = bool(parse_issue_key_reference(target_memory_ref)) or transcript_has_issue_key_reference(
|
||||
@@ -716,6 +718,9 @@ def harden_voice_task_intent(parsed, transcript):
|
||||
|
||||
|
||||
def voice_task_has_safe_existing_task_anchor(draft, transcript):
|
||||
if draft.get("target_task_id"):
|
||||
return True
|
||||
|
||||
target_memory_ref = normalize_string(draft.get("target_memory_ref"), 80)
|
||||
return bool(
|
||||
parse_issue_key_reference(target_memory_ref)
|
||||
@@ -971,6 +976,26 @@ def resolve_voice_task_assignee(project, draft):
|
||||
return serialize_resolved_assignee(best_member, best_score, "assignee_hint")
|
||||
|
||||
|
||||
def resolve_explicit_voice_task_assignees(project, draft):
|
||||
if "assignee_ids" not in draft:
|
||||
return None
|
||||
|
||||
assignee_ids = draft.get("assignee_ids") if isinstance(draft.get("assignee_ids"), list) else []
|
||||
if not assignee_ids:
|
||||
return []
|
||||
|
||||
member_by_id = {
|
||||
str(project_member.member_id): project_member.member
|
||||
for project_member in get_voice_task_project_assignable_members(project)
|
||||
}
|
||||
|
||||
return [
|
||||
serialize_resolved_assignee(member_by_id[assignee_id], 1.0, "explicit_assignee_ids")
|
||||
for assignee_id in assignee_ids
|
||||
if assignee_id in member_by_id
|
||||
]
|
||||
|
||||
|
||||
def transcript_requests_all_project_assignees(transcript, draft=None):
|
||||
normalized = normalize_match_value(transcript)
|
||||
assignee_hint = normalize_match_value((draft or {}).get("assignee_hint"))
|
||||
@@ -988,6 +1013,10 @@ def transcript_requests_all_project_assignees(transcript, draft=None):
|
||||
|
||||
|
||||
def resolve_voice_task_assignees(project, draft, transcript=None):
|
||||
explicit_assignees = resolve_explicit_voice_task_assignees(project, draft)
|
||||
if explicit_assignees is not None:
|
||||
return explicit_assignees
|
||||
|
||||
if transcript_requests_all_project_assignees(transcript, draft):
|
||||
return [
|
||||
serialize_resolved_assignee(project_member.member, 1.0, "all_project_members")
|
||||
@@ -1081,8 +1110,14 @@ def resolve_voice_task_state(project, draft, allow_default=True):
|
||||
if not project:
|
||||
return None
|
||||
|
||||
state_hint = draft.get("state_hint")
|
||||
states = list(State.objects.filter(project=project).order_by("sequence"))
|
||||
explicit_state_id = normalize_uuid_string(draft.get("state_id"))
|
||||
if explicit_state_id:
|
||||
explicit_state = next((state for state in states if str(state.id) == explicit_state_id), None)
|
||||
if explicit_state:
|
||||
return serialize_resolved_state(explicit_state, 1.0, "explicit_state_id")
|
||||
|
||||
state_hint = draft.get("state_hint")
|
||||
if state_hint:
|
||||
best_state = None
|
||||
best_score = 0.0
|
||||
@@ -1452,9 +1487,22 @@ def find_latest_voice_task_issue(memory_sessions, project_id=None):
|
||||
|
||||
def resolve_voice_task_memory_target(workspace, user, draft, current_session=None, client_context=None, transcript=None):
|
||||
target_memory_ref = normalize_string(draft.get("target_memory_ref"), 80)
|
||||
explicit_target_task_id = normalize_uuid_string(draft.get("target_task_id"))
|
||||
memory_sessions = get_committed_voice_task_memory_sessions(workspace, user, current_session=current_session)
|
||||
generic_memory_reference = transcript_has_generic_memory_reference(transcript)
|
||||
|
||||
if explicit_target_task_id:
|
||||
target_issue = (
|
||||
Issue.issue_objects.filter(workspace=workspace, id=explicit_target_task_id)
|
||||
.select_related("project")
|
||||
.first()
|
||||
)
|
||||
if (
|
||||
is_voice_task_issue_available(target_issue)
|
||||
and get_accessible_projects(workspace, user).filter(id=target_issue.project_id).exists()
|
||||
):
|
||||
return target_issue, "explicit_target_task_id", None
|
||||
|
||||
if target_memory_ref:
|
||||
target_uuid = None
|
||||
try:
|
||||
@@ -1523,6 +1571,8 @@ def voice_task_has_update_fields(draft, resolution):
|
||||
or draft.get("due_time")
|
||||
or (draft.get("priority") and draft.get("priority") != "none")
|
||||
or draft.get("checklist")
|
||||
or "assignee_ids" in draft
|
||||
or draft.get("state_id")
|
||||
or (resolution.get("assignee") and resolution["assignee"]["confidence"] >= VOICE_TASK_ASSIGNEE_MATCH_THRESHOLD)
|
||||
or (draft.get("state_hint") and resolution.get("state") and resolution["state"]["confidence"] >= VOICE_TASK_STATE_MATCH_THRESHOLD)
|
||||
or resolution.get("labels")
|
||||
@@ -1846,7 +1896,13 @@ def build_voice_task_issue_update_payload(issue, draft, resolution, transcript=N
|
||||
if draft.get("priority") and draft["priority"] != "none":
|
||||
payload["priority"] = draft["priority"]
|
||||
|
||||
if assignees:
|
||||
if "assignee_ids" in draft:
|
||||
payload["assignee_ids"] = [
|
||||
assignee["id"]
|
||||
for assignee in assignees
|
||||
if assignee and assignee["confidence"] >= VOICE_TASK_ASSIGNEE_MATCH_THRESHOLD
|
||||
]
|
||||
elif assignees:
|
||||
payload["assignee_ids"] = [
|
||||
assignee["id"]
|
||||
for assignee in assignees
|
||||
@@ -1855,7 +1911,7 @@ def build_voice_task_issue_update_payload(issue, draft, resolution, transcript=N
|
||||
elif assignee and assignee["confidence"] >= VOICE_TASK_ASSIGNEE_MATCH_THRESHOLD:
|
||||
payload["assignee_ids"] = [assignee["id"]]
|
||||
|
||||
if (draft.get("state_hint") or project_change) and state and state["confidence"] >= VOICE_TASK_STATE_MATCH_THRESHOLD:
|
||||
if (draft.get("state_hint") or draft.get("state_id") or project_change) and state and state["confidence"] >= VOICE_TASK_STATE_MATCH_THRESHOLD:
|
||||
payload["state_id"] = state["id"]
|
||||
|
||||
if labels:
|
||||
@@ -2043,6 +2099,29 @@ def normalize_string(value, max_length=None):
|
||||
return normalized[:max_length] if max_length else normalized
|
||||
|
||||
|
||||
def normalize_uuid_string(value):
|
||||
normalized = normalize_string(value, 80)
|
||||
if not normalized:
|
||||
return None
|
||||
|
||||
try:
|
||||
return str(uuid.UUID(normalized))
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def normalize_uuid_list(value, limit=50):
|
||||
if not isinstance(value, list):
|
||||
return []
|
||||
|
||||
result = []
|
||||
for item in value[:limit]:
|
||||
normalized = normalize_uuid_string(item)
|
||||
if normalized and normalized not in result:
|
||||
result.append(normalized)
|
||||
return result
|
||||
|
||||
|
||||
def normalize_string_list(value, limit=20, item_max_length=120):
|
||||
if not isinstance(value, list):
|
||||
return []
|
||||
@@ -2097,6 +2176,9 @@ def normalize_voice_task_parse(parsed):
|
||||
normalized = {
|
||||
"intent": intent,
|
||||
"target_memory_ref": normalize_string(parsed.get("target_memory_ref"), 80),
|
||||
"project_id": normalize_uuid_string(parsed.get("project_id")),
|
||||
"state_id": normalize_uuid_string(parsed.get("state_id")),
|
||||
"target_task_id": normalize_uuid_string(parsed.get("target_task_id") or parsed.get("target_issue_id")),
|
||||
"project_hint": normalize_string(parsed.get("project_hint"), 255),
|
||||
"state_hint": normalize_string(parsed.get("state_hint"), 120),
|
||||
"assignee_hint": normalize_string(parsed.get("assignee_hint"), 255),
|
||||
@@ -2115,6 +2197,8 @@ def normalize_voice_task_parse(parsed):
|
||||
},
|
||||
"questions": normalize_string_list(parsed.get("questions"), limit=10, item_max_length=255),
|
||||
}
|
||||
if "assignee_ids" in parsed:
|
||||
normalized["assignee_ids"] = normalize_uuid_list(parsed.get("assignee_ids"))
|
||||
|
||||
return normalized
|
||||
|
||||
|
||||
Reference in New Issue
Block a user