Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbe3e870a1 | ||
|
|
caab2cabe3 | ||
|
|
3c7b88bb15 | ||
|
|
36975c6c1b | ||
|
|
6325ba88ff | ||
|
|
f8b6196205 | ||
|
|
aa0d22bbe2 |
@@ -45,3 +45,16 @@ export function unbindWorkWechat() {
|
||||
export function changeFirstPassword(params: { password: string; password_confirm: string }) {
|
||||
return request.post({ url: '/login/changeFirstPassword', params })
|
||||
}
|
||||
|
||||
// 统一账号登录开关和服务器生成的固定登录入口
|
||||
export function getIamConfig() {
|
||||
return request.get({ url: '/iam/config' }, { withToken: false })
|
||||
}
|
||||
|
||||
// 浏览器绑定的一次性兑换码;不重试,也不将旧业务 token 带入认证
|
||||
export function iamLogin(ticket: string) {
|
||||
return request.post(
|
||||
{ url: '/iam/exchange', params: { ticket, terminal: config.terminal }, withCredentials: true },
|
||||
{ withToken: false, isOpenRetry: false }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
import { getUserInfo, login, logout, workWechatLogin } from '@/api/user'
|
||||
import { getUserInfo, iamLogin, login, logout, workWechatLogin } from '@/api/user'
|
||||
import { TOKEN_KEY } from '@/enums/cacheEnums'
|
||||
import { PageEnum } from '@/enums/pageEnum'
|
||||
import router, { filterAsyncRoutes } from '@/router'
|
||||
@@ -83,6 +83,13 @@ const useUserStore = defineStore({
|
||||
})
|
||||
})
|
||||
},
|
||||
async iamLogin(ticket: string) {
|
||||
const data = await iamLogin(ticket)
|
||||
this.token = data.token
|
||||
this.isPaw = data.is_paw ?? 1
|
||||
cache.set(TOKEN_KEY, data.token)
|
||||
return data
|
||||
},
|
||||
getUserInfo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
getUserInfo()
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
<div class="text-center text-3xl font-medium mb-8">{{ config.web_name }}</div>
|
||||
|
||||
<!-- 企业微信自动授权中 -->
|
||||
<div v-if="wxWorkAutoLogin" class="text-center py-10">
|
||||
<div v-if="wxWorkAutoLogin || iamLoading" class="text-center py-10">
|
||||
<el-icon class="is-loading mb-4" :size="40" color="var(--el-color-primary)">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
<div class="text-gray-500">企业微信授权登录中...</div>
|
||||
<div class="text-gray-500">{{ iamLoading ? '统一账号登录中...' : '企业微信授权登录中...' }}</div>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
@@ -78,6 +78,20 @@
|
||||
请使用企业微信扫描二维码登录
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<section v-if="iamEnabled" class="iam-login-alternative" aria-label="其他登录方式">
|
||||
<div class="iam-login-divider" aria-hidden="true">其他登录方式</div>
|
||||
<el-button class="iam-login-entry" size="large" @click="handleIamLogin">
|
||||
<span class="iam-login-entry__content">
|
||||
<icon name="local-icon-anquan" size="22" />
|
||||
<span>统一账号快捷登录</span>
|
||||
</span>
|
||||
<span class="iam-login-entry__arrow" aria-hidden="true">
|
||||
<icon name="el-icon-ArrowRight" size="16" />
|
||||
</span>
|
||||
</el-button>
|
||||
<p class="iam-login-hint">使用统一身份平台账号登录</p>
|
||||
</section>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -99,7 +113,7 @@ import LayoutFooter from '@/layout/components/footer.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import cache from '@/utils/cache'
|
||||
import { getWorkWechatConfig } from '@/api/user'
|
||||
import { getIamConfig, getWorkWechatConfig } from '@/api/user'
|
||||
|
||||
const passwordRef = shallowRef<InputInstance>()
|
||||
const formRef = shallowRef<FormInstance>()
|
||||
@@ -118,6 +132,66 @@ const rules = {
|
||||
password: [{ required: true, message: '请输入密码', trigger: ['blur'] }]
|
||||
}
|
||||
|
||||
// 统一账号登录是可选入口,不取代账号密码或企业微信登录。
|
||||
const iamEnabled = ref(false)
|
||||
const iamLoginUrl = ref('')
|
||||
const iamLoading = ref(false)
|
||||
let iamCallbackHandled = false
|
||||
|
||||
const loadIamConfig = async () => {
|
||||
try {
|
||||
const result = await getIamConfig()
|
||||
const url = new URL(result?.loginUrl || '', window.location.origin)
|
||||
if (result?.enabled === true && url.protocol === 'https:') {
|
||||
iamLoginUrl.value = url.href
|
||||
iamEnabled.value = true
|
||||
}
|
||||
} catch {
|
||||
// IAM 不可用时,原有登录入口保持可用。
|
||||
}
|
||||
}
|
||||
|
||||
const handleIamLogin = () => {
|
||||
if (iamEnabled.value && iamLoginUrl.value) {
|
||||
window.location.assign(iamLoginUrl.value)
|
||||
}
|
||||
}
|
||||
|
||||
const handleIamCallback = async (ticket: string | null, error: string | null) => {
|
||||
if (iamCallbackHandled) return
|
||||
iamCallbackHandled = true
|
||||
// 在任何 await 和兑换前移除票据,刷新不会重复兑换;保留其他 query/hash。
|
||||
const cleanUrl = new URL(window.location.href)
|
||||
cleanUrl.searchParams.delete('iam_ticket')
|
||||
cleanUrl.searchParams.delete('iam_error')
|
||||
// 同一回调不得随后被识别为企业微信授权。
|
||||
cleanUrl.searchParams.delete('code')
|
||||
cleanUrl.searchParams.delete('state')
|
||||
window.history.replaceState(window.history.state, '', cleanUrl.pathname + cleanUrl.search + cleanUrl.hash)
|
||||
if (error || !ticket) {
|
||||
ElMessage.error(error || '统一账号登录凭证无效,请重新登录')
|
||||
return
|
||||
}
|
||||
iamLoading.value = true
|
||||
try {
|
||||
const result = await userStore.iamLogin(ticket)
|
||||
if (result.is_paw === 0) {
|
||||
await router.push('/change-password')
|
||||
return
|
||||
}
|
||||
if (result.need_bind_work_wechat) {
|
||||
await router.push('/bind-work-wechat')
|
||||
return
|
||||
}
|
||||
redirectAfterLogin()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error?.msg || error?.message || '统一账号登录失败,请重新登录或使用账号密码')
|
||||
loginMode.value = 'account'
|
||||
} finally {
|
||||
iamLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 企业微信相关
|
||||
const loginMode = ref<'account' | 'wxwork'>('account')
|
||||
const wxWorkEnabled = ref(false)
|
||||
@@ -243,7 +317,12 @@ onMounted(async () => {
|
||||
|
||||
// 检查 URL 中是否有企业微信回调 code
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const wxCode = urlParams.get('code')
|
||||
void loadIamConfig()
|
||||
const hasIamCallback = urlParams.has('iam_ticket') || urlParams.has('iam_error')
|
||||
if (hasIamCallback) {
|
||||
await handleIamCallback(urlParams.get('iam_ticket'), urlParams.get('iam_error'))
|
||||
}
|
||||
const wxCode = hasIamCallback ? null : urlParams.get('code')
|
||||
const wxState = urlParams.get('state')
|
||||
|
||||
if (wxCode && wxState === 'admin_login') {
|
||||
@@ -263,7 +342,7 @@ onMounted(async () => {
|
||||
wxWorkConfig.value = { corp_id: res.corp_id, agent_id: res.agent_id }
|
||||
|
||||
// 在企业微信内:自动跳转 OAuth 授权
|
||||
if (isInWxWork()) {
|
||||
if (isInWxWork() && !hasIamCallback) {
|
||||
const redirectUri = encodeURIComponent(getRedirectUri())
|
||||
const authUrl =
|
||||
`https://open.weixin.qq.com/connect/oauth2/authorize` +
|
||||
@@ -286,6 +365,82 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.iam-login-alternative {
|
||||
margin-top: 28px;
|
||||
}
|
||||
|
||||
.iam-login-divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
margin-bottom: 18px;
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: var(--el-border-color-light);
|
||||
}
|
||||
}
|
||||
|
||||
.iam-login-entry.el-button {
|
||||
--el-button-bg-color: var(--el-color-primary-light-9);
|
||||
--el-button-text-color: var(--el-color-primary);
|
||||
--el-button-border-color: var(--el-color-primary-light-5);
|
||||
--el-button-hover-bg-color: var(--el-color-primary-light-8);
|
||||
--el-button-hover-text-color: var(--el-color-primary);
|
||||
--el-button-hover-border-color: var(--el-color-primary);
|
||||
--el-button-active-bg-color: var(--el-color-primary-light-8);
|
||||
--el-button-active-border-color: var(--el-color-primary);
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 48px;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
padding: 12px 34px;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
transition: background-color 150ms ease, border-color 150ms ease;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--el-color-primary);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.iam-login-entry__content {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.iam-login-entry__arrow {
|
||||
position: absolute;
|
||||
right: 14px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.iam-login-hint {
|
||||
margin: 14px 0 0;
|
||||
text-align: center;
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.iam-login-entry.el-button {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.login {
|
||||
background-image: url('./images/login_bg.png');
|
||||
@apply min-h-screen bg-no-repeat bg-center bg-cover;
|
||||
|
||||
@@ -233,8 +233,29 @@ class DoctorRepository(Protocol):
|
||||
) -> dict[str, Any]:
|
||||
"""Append one model-specific AI diagnosis snapshot for one patient."""
|
||||
|
||||
def get_prescription(self, prescription_id: int) -> Prescription:
|
||||
"""Return one issued prescription."""
|
||||
def get_prescription(self, prescription_id: int) -> Prescription:
|
||||
"""Return one issued prescription."""
|
||||
|
||||
def list_prescription_ai_statuses(self, ids: list[int]) -> dict[str, Any]:
|
||||
"""Read cached dual-model states for up to 100 prescriptions."""
|
||||
|
||||
def list_prescription_ai_reports(self, *, prescription_id: int = 0, diagnosis_id: int = 0, page_no: int = 1, page_size: int = 20) -> dict[str, Any]:
|
||||
"""Read immutable analysis batch history in the authorized scope."""
|
||||
|
||||
def get_prescription_ai_report(self, batch_id: int) -> dict[str, Any]:
|
||||
"""Read one analysis batch without starting model work."""
|
||||
|
||||
def regenerate_prescription_ai(self, prescription_id: int, reason: str) -> dict[str, Any]:
|
||||
"""Explicitly request a new analysis batch with a reason."""
|
||||
|
||||
def retry_prescription_ai(self, batch_id: int, model_key: str) -> dict[str, Any]:
|
||||
"""Retry only the requested failed model."""
|
||||
|
||||
def review_prescription_ai(self, batch_id: int, model_key: str, status: str, comment: str) -> dict[str, Any]:
|
||||
"""Save a doctor's review separately from immutable AI output."""
|
||||
|
||||
def prescription_ai_statistics(self, date_from: str, date_to: str, doctor_id: int | None = None) -> dict[str, Any]:
|
||||
"""Read baseline agreement statistics, never diagnostic accuracy."""
|
||||
|
||||
def create_prescription(
|
||||
self,
|
||||
@@ -1574,14 +1595,55 @@ class RemoteDoctorRepository:
|
||||
payload, Prescription.from_dict, page_no=page_no, page_size=page_size
|
||||
)
|
||||
|
||||
def get_prescription(self, prescription_id: int) -> Prescription:
|
||||
"""Load one issued prescription using ``tcm.prescription/detail``."""
|
||||
def get_prescription(self, prescription_id: int) -> Prescription:
|
||||
"""Load one issued prescription using ``tcm.prescription/detail``."""
|
||||
|
||||
result = _require_mapping(
|
||||
self.client.get("tcm.prescription/detail", {"id": prescription_id}),
|
||||
"tcm.prescription/detail",
|
||||
)
|
||||
return Prescription.from_dict(result)
|
||||
return Prescription.from_dict(result)
|
||||
|
||||
def _prescription_ai_request(self, action: str, params: dict[str, Any], *, mutation: bool = False) -> dict[str, Any]:
|
||||
endpoint = f"tcm.prescriptionAi/{action}"
|
||||
payload = _client_request(self.client, "post" if mutation else "get", endpoint, params, timeout=30.0)
|
||||
return dict(_require_mapping(payload, endpoint))
|
||||
|
||||
def list_prescription_ai_statuses(self, ids: list[int]) -> dict[str, Any]:
|
||||
if len(ids) > 100 or any(int(value) <= 0 for value in ids):
|
||||
raise ValueError("statuses requires at most 100 positive prescription IDs")
|
||||
return self._prescription_ai_request("statuses", {"ids": ",".join(str(int(value)) for value in dict.fromkeys(ids))})
|
||||
|
||||
def list_prescription_ai_reports(self, *, prescription_id: int = 0, diagnosis_id: int = 0, page_no: int = 1, page_size: int = 20) -> dict[str, Any]:
|
||||
if bool(prescription_id) == bool(diagnosis_id):
|
||||
raise ValueError("Exactly one prescription_id or diagnosis_id is required")
|
||||
params = {"prescription_id": prescription_id} if prescription_id else {"diagnosis_id": diagnosis_id}
|
||||
params.update(page_no=page_no, page_size=page_size)
|
||||
return self._prescription_ai_request("reports", params)
|
||||
|
||||
def get_prescription_ai_report(self, batch_id: int) -> dict[str, Any]:
|
||||
return self._prescription_ai_request("detail", {"batch_id": batch_id})
|
||||
|
||||
def regenerate_prescription_ai(self, prescription_id: int, reason: str) -> dict[str, Any]:
|
||||
if not reason.strip():
|
||||
raise ValueError("重新分析需要填写原因")
|
||||
return self._prescription_ai_request("regenerate", {"prescription_id": prescription_id, "reason": reason.strip()}, mutation=True)
|
||||
|
||||
def retry_prescription_ai(self, batch_id: int, model_key: str) -> dict[str, Any]:
|
||||
if model_key not in {"qwen", "openai"}:
|
||||
raise ValueError("Unknown model_key")
|
||||
return self._prescription_ai_request("retry", {"batch_id": batch_id, "model_key": model_key}, mutation=True)
|
||||
|
||||
def review_prescription_ai(self, batch_id: int, model_key: str, status: str, comment: str) -> dict[str, Any]:
|
||||
if model_key not in {"qwen", "openai"} or status not in {"viewed", "needs_information", "not_adopted", "reviewed"}:
|
||||
raise ValueError("Invalid review state")
|
||||
return self._prescription_ai_request("review", {"batch_id": batch_id, "model_key": model_key, "status": status, "comment": comment}, mutation=True)
|
||||
|
||||
def prescription_ai_statistics(self, date_from: str, date_to: str, doctor_id: int | None = None) -> dict[str, Any]:
|
||||
params: dict[str, Any] = {"date_from": date_from, "date_to": date_to}
|
||||
if doctor_id is not None:
|
||||
params["doctor_id"] = doctor_id
|
||||
return self._prescription_ai_request("statistics", params)
|
||||
|
||||
def create_prescription(
|
||||
self,
|
||||
|
||||
@@ -5729,6 +5729,7 @@ class AiConsultDialog(QDialog):
|
||||
"usage_notes",
|
||||
}
|
||||
seed.update({key: deepcopy(value) for key, value in draft.items() if key in allowed})
|
||||
seed["ai_assisted"] = True
|
||||
dialog = PrescriptionEditorDialog(
|
||||
self.repository,
|
||||
seed,
|
||||
|
||||
@@ -78,6 +78,7 @@ from ..widgets import (
|
||||
page_total,
|
||||
run_async,
|
||||
)
|
||||
from .issued_prescription_ai import can_open_issued_ai, present_issued_prescription_ai
|
||||
from .local_audio_queue import LocalAudioQueueDialog
|
||||
from .prescription_ai import can_open_diagnosis_ai_report, present_diagnosis_ai_report
|
||||
|
||||
@@ -1067,6 +1068,12 @@ class DiagnosisDialog(QDialog):
|
||||
self.readonly_ai_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.readonly_ai_button.clicked.connect(self._open_ai_report)
|
||||
heading_row.addWidget(self.readonly_ai_button, 0)
|
||||
self.readonly_prescription_ai_button = QPushButton("处方 AI 对照", card)
|
||||
self.readonly_prescription_ai_button.setProperty("variant", "secondary")
|
||||
self.readonly_prescription_ai_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.readonly_prescription_ai_button.setVisible(can_open_issued_ai(self.permissions) and callable(getattr(self.repository, "list_prescription_ai_reports", None)))
|
||||
self.readonly_prescription_ai_button.clicked.connect(self._open_prescription_ai_report)
|
||||
heading_row.addWidget(self.readonly_prescription_ai_button, 0)
|
||||
layout.addLayout(heading_row)
|
||||
patient_hero = QFrame()
|
||||
patient_hero.setObjectName("DiagnosisReadonlyPatientHero")
|
||||
@@ -1709,6 +1716,9 @@ class DiagnosisDialog(QDialog):
|
||||
if hasattr(self, "readonly_ai_button"):
|
||||
self.readonly_ai_button.setVisible(can_open_diagnosis_ai_report(self.permissions))
|
||||
self.readonly_ai_button.setEnabled(self._diagnosis_id > 0)
|
||||
if hasattr(self, "readonly_prescription_ai_button"):
|
||||
self.readonly_prescription_ai_button.setVisible(can_open_issued_ai(self.permissions) and callable(getattr(self.repository, "list_prescription_ai_reports", None)))
|
||||
self.readonly_prescription_ai_button.setEnabled(self._diagnosis_id > 0)
|
||||
previous_key = self._current_tab_key()
|
||||
allowed_tabs = [
|
||||
(key, label) for key, label, codes in _TAB_DEFINITIONS if self._tab_allowed(codes)
|
||||
@@ -1960,6 +1970,10 @@ class DiagnosisDialog(QDialog):
|
||||
)
|
||||
present_diagnosis_ai_report(self.repository, self.permissions, self, row)
|
||||
|
||||
def _open_prescription_ai_report(self) -> None:
|
||||
if self._diagnosis_id > 0:
|
||||
present_issued_prescription_ai(self.repository, self.permissions, self, diagnosis_id=self._diagnosis_id)
|
||||
|
||||
def open_view_only(
|
||||
self,
|
||||
diagnosis_id: int,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,285 @@
|
||||
"""Presentation-only Chinese labels for saved prescription analysis payloads.
|
||||
|
||||
Keep source identifiers, enum keys and statistics untouched in the repository data.
|
||||
Only explicitly structured metadata is localized; clinical prose is not translated.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
SOURCE_LABELS = {
|
||||
"diagnoses": "诊单", "doctor_notes": "医生笔记", "tracking_notes": "随访记录",
|
||||
"prescriptions": "历史处方", "call_records": "问诊通话", "video_calls": "视频问诊",
|
||||
"transcript_segments": "转写片段", "chat_records": "聊天记录", "daily_records": "日常记录",
|
||||
"blood_records": "血糖血压记录", "blood_glucose_pressure": "血糖血压记录",
|
||||
"diet_records": "饮食记录", "diet": "饮食记录", "exercise_records": "运动记录", "exercise": "运动记录",
|
||||
"im_messages": "即时聊天记录", "tencent_im": "即时聊天记录",
|
||||
"wechat_messages": "企业微信聊天记录", "wechat_work": "企业微信聊天记录",
|
||||
"target_plan": "本次处方方案", "clinical": "临床资料", "file": "附件",
|
||||
"tongue": "舌象", "tongue_image": "舌象图片", "tongue_images": "舌象图片",
|
||||
"clinical_attachment": "临床附件", "patient": "患者资料",
|
||||
}
|
||||
|
||||
SYSTEM_LABELS = {
|
||||
"SOURCE_HISTORY_VERSIONS_UNAVAILABLE": "来源历史版本无法核验",
|
||||
"ARCHIVE_SYNC_WATERMARK_UNAVAILABLE": "归档同步完整性尚未核验",
|
||||
"TRANSCRIPT_NOT_VERIFIED_COMPLETE": "问诊转写完整性尚未核验",
|
||||
"TRANSCRIPT_NOT_FINAL": "问诊转写尚未完整归档",
|
||||
"TRANSCRIPT_PARTIAL": "问诊转写仅部分完成", "TRANSCRIPT_FAILED": "问诊转写失败",
|
||||
"TRANSCRIPT_RUNNING": "问诊转写进行中", "TRANSCRIPT_PENDING": "等待问诊转写",
|
||||
"SOURCE_AUTHORIZATION_LINK_UNAVAILABLE": "来源缺少可核验的授权关联",
|
||||
"SOURCE_PATIENT_CONFLICT": "来源的患者关联存在冲突",
|
||||
"SOURCE_ACCESS_RESTRICTED": "来源访问受限",
|
||||
"UNLINKED_SOURCE_REQUIRES_AUTHORIZATION": "未关联来源需核验访问权限",
|
||||
"SOURCE_READ_UNAVAILABLE": "来源暂时无法读取",
|
||||
"ATTACHMENT_TARGET_PLAN_LEAKAGE_UNVERIFIED": "附件可能包含本次处方,独立性未核验",
|
||||
"UNSTRUCTURED_TARGET_PLAN_LEAKAGE_UNVERIFIED": "非结构化资料可能包含本次处方,独立性未核验",
|
||||
"TARGET_PLAN_COPY_ISOLATED": "已隔离资料中复制的本次处方内容",
|
||||
"CRITICAL_CLINICAL_FACT_MISSING": "关键临床资料缺失",
|
||||
"FILE_STORAGE_AUTHORIZATION_UNVERIFIED": "附件存储访问权限尚未核验",
|
||||
"FILE_CONTENT_VERSION_UNVERIFIED": "附件内容版本尚未核验",
|
||||
"PATIENT_BINDING_REQUIRED": "需完善患者与诊单关联",
|
||||
"PATIENT_BINDING_OR_PERMISSION_REQUIRED": "需核验患者关联与资料访问权限",
|
||||
"ACCESS_REVOKED": "资料访问权限已变更", "SOURCE_CHANGED": "资料或处方已更新,请查看新版本",
|
||||
"BUDGET_PAUSED": "已达到分析预算,等待额度恢复",
|
||||
"CONFIG_INVALID": "模型配置无效,请联系管理员", "CONFIG_DISABLED": "模型分析尚未启用",
|
||||
"UPSTREAM_AUTH_FAILED": "模型服务认证失败,请联系管理员",
|
||||
"UPSTREAM_TIMEOUT": "模型响应超时,可稍后重试", "UPSTREAM_BUSY": "模型服务繁忙,可稍后重试",
|
||||
"UPSTREAM_UNAVAILABLE": "模型服务暂不可用", "UPSTREAM_REJECTED": "模型服务未接受本次请求",
|
||||
"UPSTREAM_FAILED": "模型服务处理失败", "EMPTY_RESPONSE": "模型未返回内容",
|
||||
"INCOMPLETE_RESPONSE": "模型返回内容不完整", "INVALID_RESPONSE": "模型返回内容未通过校验",
|
||||
"RESPONSE_INVALID": "模型返回内容未通过校验", "INVALID_REPORT_OUTPUT": "模型报告未通过格式校验",
|
||||
"INVALID_EVIDENCE_OUTPUT": "模型证据来源未通过校验",
|
||||
"INVALID_FILE_EVIDENCE_OUTPUT": "模型附件证据未通过校验",
|
||||
"CONTEXT_TOO_LARGE": "资料超过本次处理预算",
|
||||
"INPUT_TOKEN_BUDGET_EXCEEDED": "输入资料超过本次处理预算",
|
||||
"SYNTHESIS_BUDGET_EXCEEDED": "资料汇总超过本次处理预算",
|
||||
"FINAL_CONTEXT_EXCEEDS_BUDGET": "来源与缺口说明超过汇总预算,请联系管理员",
|
||||
"TOTAL_CALL_BUDGET_EXCEEDED": "模型调用次数达到本次上限",
|
||||
"SOURCE_UNIT_EXCEEDS_BUDGET": "单条来源资料超过处理预算",
|
||||
"RESPONSE_SIZE_EXCEEDED": "模型返回内容超过长度上限",
|
||||
"LEASE_EXPIRED": "工作进程中断,任务等待恢复",
|
||||
"SOURCE_PREPARATION_FAILED": "来源资料准备失败", "INTERNAL_ERROR": "分析处理异常,可稍后重试",
|
||||
"GENERATION_FAILED": "报告生成失败,可稍后重试", "CHECKPOINT_REJECTED": "分析进度保存未通过校验",
|
||||
"INVALID_PROFILE": "模型配置未通过校验", "INVALID_FROZEN_CONTEXT": "冻结资料未通过校验",
|
||||
"INVALID_FILE_MANIFEST": "附件清单未通过校验", "SOURCE_GAP": "来源资料存在缺口",
|
||||
"FILE_CAPABILITY_DISABLED": "模型附件处理能力尚未启用",
|
||||
"FILE_UNAVAILABLE_OR_UNSUPPORTED": "附件不可用或格式不受支持",
|
||||
"FILE_TYPE_UNSUPPORTED": "附件格式不受支持",
|
||||
"STRICT_FILES_INVALID_OR_LIMIT": "附件校验未通过或超过处理上限",
|
||||
"FILE_DELIVERY_UNVERIFIED": "附件送达情况尚未核验",
|
||||
"MODEL_REPORTED_UNREADABLE": "模型无法读取附件", "MODEL_REPORTED_UNSUPPORTED": "模型不支持此附件",
|
||||
"MODEL_FILE_OUTPUT_INVALID": "模型未能正确解析这组附件",
|
||||
"AI_ANALYSIS_CIPHER_INVALID": "报告加密数据无法读取",
|
||||
"AI_ANALYSIS_ENCRYPTION_FAILED": "报告加密保存失败",
|
||||
"AI_ANALYSIS_KEY_INVALID": "报告加密配置无效", "AI_ANALYSIS_KEY_UNAVAILABLE": "报告加密配置不可用",
|
||||
"formulation_mismatch": "剂型不同,未提供经确认的换算规则",
|
||||
"dose_basis_mismatch": "剂量基准不同", "unit_mismatch": "剂量单位不同",
|
||||
"unknown_formulation": "剂型缺失或不受支持", "empty_prescription": "处方为空或药味结构无效",
|
||||
"catalog_unavailable": "缺少可用的药材字典", "invalid_herb": "药味结构无效",
|
||||
"ambiguous_herb_name": "药名存在多种字典匹配", "unknown_herb_name": "药名未匹配药材字典",
|
||||
"doctor_identity_mismatch": "医生药材编号与规范药名不一致",
|
||||
"processing_conflict": "炮制信息与药材字典冲突或无效",
|
||||
"ambiguous_herb_role": "主辅方、给药途径或分组不明确",
|
||||
"missing_or_unknown_unit": "剂量单位缺失或不受支持",
|
||||
"missing_or_unknown_dose_basis": "每剂或每日剂量基准不明确",
|
||||
"invalid_dosage": "剂量数值无效", "invalid_herb_usage": "药味煎服说明格式无效",
|
||||
"duplicate_semantics_conflict": "重复药项的单位、剂量基准或煎服说明不一致",
|
||||
"no_medication": "建议暂不使用药物", "no_medication_recommended": "建议暂不使用药物",
|
||||
"baseline_ineligible": "不符合独立基线统计条件", "incomplete_coverage": "资料覆盖不完整",
|
||||
"missing_result": "缺少模型结果", "invalid_score": "一致度分值无效",
|
||||
"missing_algorithm_version": "缺少算法版本", "transcript_not_final": "问诊转写尚未完整归档",
|
||||
"event_patient_conflict": "开方事件的患者关联冲突", "duplicate_baseline_conflict": "重复基线结果存在冲突",
|
||||
"review_conflict": "复核记录存在冲突", "review_not_completed": "复核尚未完成",
|
||||
"review_not_independent": "复核不具独立性", "review_disputed": "复核存在争议",
|
||||
"review_not_evaluable": "复核不可评价", "invalid_review_outcome": "复核结论无效",
|
||||
"unknown_review_sampling": "复核抽样方式未确认", "start_at_required": "需设置分析起始时间",
|
||||
"processed": "已处理", "restricted": "访问受限", "error": "处理失败", "timeout": "处理超时",
|
||||
"delivered": "已送达", "unreadable": "不可读", "unsupported": "不支持", "parsed": "已解析",
|
||||
"ok": "可比条件已通过", "doctor": "医生方", "candidate": "候选方", "both": "双方",
|
||||
"low": "低风险", "medium": "中风险", "high": "高风险", "none": "无",
|
||||
"main": "主方", "oral": "口服", "external": "外用",
|
||||
"raw": "生品", "image": "图片", "document": "文档", "remote_url": "远程附件",
|
||||
"stratified_versions": "按版本分层统计", "single_version": "单一版本", "no_valid_samples": "无有效样本",
|
||||
"no_samples": "未建立复核样本", "recorded": "已记录", "conflict": "存在冲突",
|
||||
"not_evaluable": "不可评价", "qualified": "合格", "needs_revision": "需修订", "unqualified": "不合格",
|
||||
"random": "随机抽样", "stratified": "分层抽样", "risk_directed": "按风险抽样",
|
||||
"stratified_sampling": "按抽样方式分层统计",
|
||||
"spelling_aliases_only_no_quantity_conversion": "仅规范单位写法,不进行剂量换算",
|
||||
"g": "克", "mg": "毫克", "kg": "千克", "ml": "毫升", "mL": "毫升", "l": "升", "L": "升",
|
||||
"qwen": "千问", "openai": "OpenAI",
|
||||
}
|
||||
|
||||
EXTRA_FIELD_LABELS = {
|
||||
"source": "来源", "code": "原因说明", "reason_code": "原因说明", "error_code": "错误原因",
|
||||
"error_message": "错误说明", "message": "说明", "detail": "详情", "details": "详细记录",
|
||||
"reason_message": "原因说明", "field": "字段", "value": "记录值", "side": "所属处方",
|
||||
"row": "药项序号", "rows": "逐味记录", "key": "药项标识", "id": "编号", "medicine_id": "药材编号",
|
||||
"prescription_id": "处方编号", "diagnosis_id": "诊单编号", "patient_id": "患者编号",
|
||||
"doctor_id": "医生编号", "doctor_name": "医生姓名", "model_key": "模型", "model_name": "模型名称",
|
||||
"configured_model_name": "配置的模型名称", "comparison_status": "可比状态", "coverage_status": "资料覆盖状态",
|
||||
"comparison_type": "比较类型", "validity": "报告有效性", "version_verified": "内容版本已核验",
|
||||
"source_record_count": "来源记录总数", "missing_count": "资料缺口数", "snapshot_complete": "资料快照完整",
|
||||
"may_be_truncated": "资料可能截断", "history_versioning": "历史版本核验", "archive_sync_verified": "归档同步已核验",
|
||||
"file_ids": "附件编号", "evidence_file_ids": "证据附件编号", "covered_source_ids": "已覆盖来源编号",
|
||||
"source_kind": "来源类型", "kind": "来源类型", "type": "类型", "purpose": "用途",
|
||||
"transfer_method": "附件传递方式", "content_hash": "内容指纹", "dictionary_hash": "药材字典指纹",
|
||||
"source_hash": "来源指纹", "url": "附件地址", "uri": "附件地址", "path": "附件路径",
|
||||
"age": "年龄", "gender": "性别", "gender_label": "性别说明", "allergy_history": "过敏史",
|
||||
"pregnancy_history": "妊娠与哺乳情况", "current_medications": "当前用药",
|
||||
"allergy_history_text": "过敏史正文", "allergy_history_desc": "过敏史说明",
|
||||
"pregnancy_history_text": "妊娠与哺乳正文", "pregnancy_history_desc": "妊娠与哺乳说明",
|
||||
"current_medicine": "当前用药", "current_medication": "当前用药",
|
||||
"prescription": "处方", "prescription_opinion": "处方意见", "prescription_advice": "处方建议",
|
||||
"treatment_principle": "治则", "doctor_advice": "医嘱", "prescription_date": "开方日期",
|
||||
"issues": "需核对问题", "formulation": "剂型", "items": "药项", "bases": "剂量基准",
|
||||
"merges": "重复药项合并", "defaults": "默认值记录", "identity_complete": "药项身份核验完整",
|
||||
"raw_herb_count": "原始药项数", "source_rows": "原始药项序号", "source_names": "原始药名",
|
||||
"original_dosages": "原始剂量", "usage": "煎服说明", "doctor": "医生方", "candidate": "候选方",
|
||||
"dictionary_versions": "药材字典版本", "unit_policy": "单位处理规则", "denominator": "一致度计算分母",
|
||||
"matched_contribution_sum": "共同药项贡献合计", "special_usage": "特殊用法",
|
||||
"decoction_instruction": "煎药说明", "usage_note": "服法备注", "before": "处理前", "after": "处理后",
|
||||
"dosage_amount": "每次用量", "dosage_unit": "每次用量单位", "dosage_bag_count": "每次袋数", "aux_usage": "辅助用法",
|
||||
"score": "药味剂量一致度", "herb_score": "纯药味重合度", "model": "模型",
|
||||
"schema_version": "资料格式版本", "decision_at": "处方决策时间", "created_at": "建立时间", "updated_at": "更新时间",
|
||||
"source_diagnosis_ids": "来源诊单编号", "redaction_manifest": "处方内容隔离清单",
|
||||
"total_count": "开方事件数", "total_events": "开方事件数", "patient_count": "患者数",
|
||||
"eligible_count": "有效比较数", "valid_count": "有效比较数", "excluded_count": "排除样本数",
|
||||
"coverage_rate": "覆盖率", "coverage_percent": "覆盖率", "paired_count": "双模型共同有效样本数",
|
||||
"excluded_reasons": "排除原因及数量", "exclusion_reasons": "排除原因及数量", "exclusion_reason": "排除原因",
|
||||
"aggregation_status": "统计汇总方式", "paired_strata": "双模型版本分层", "models": "模型统计",
|
||||
"review": "专家复核", "reviews": "专家复核", "evaluated_count": "可评价样本数", "evaluable_count": "可评价样本数",
|
||||
"qualified_count": "合格样本数", "qualified_rate": "合格率", "qualification_rate": "合格率",
|
||||
"reviewed_events": "已复核事件数", "unreviewed_events": "未复核事件数", "sampling_method": "抽样方式",
|
||||
"sampling_groups": "抽样分组", "sampling_coverage_percent": "抽样覆盖率", "outcomes": "复核结论分布",
|
||||
"outcome": "复核结论", "independent": "独立复核", "disputed": "存在争议",
|
||||
"confidence_interval": "置信区间", "confidence_interval_reason": "置信区间说明",
|
||||
"unknown_patient_events": "患者身份未确认事件数", "repeated_patient_events": "重复患者事件数",
|
||||
"invalid_row_count": "无效记录数", "metric": "统计指标",
|
||||
}
|
||||
|
||||
ENUM_FIELDS = {
|
||||
"status", "comparison_status", "coverage_status", "comparison_type", "validity", "dose_basis", "bases",
|
||||
"match_type", "match", "side", "level", "kind", "source_kind", "type", "purpose", "transfer_method",
|
||||
"sample_status", "aggregation_status", "history_versioning", "sampling_method", "outcome", "unit_policy",
|
||||
"model_key", "model", "unit", "formula_type",
|
||||
}
|
||||
REASON_FIELDS = {
|
||||
"reason", "reason_message", "reason_code", "error_code", "error_message", "code", "message",
|
||||
"missing", "missing_information", "baseline_exclusion_reasons", "excluded_reasons", "exclusion_reasons", "exclusion_reason",
|
||||
}
|
||||
SOURCE_FIELDS = {
|
||||
"source", "source_id", "source_ids", "file_id", "file_ids", "evidence_file_ids", "covered_source_ids",
|
||||
"evidence_references", "redaction_manifest",
|
||||
}
|
||||
|
||||
_MACHINE_KEY = re.compile(r"[A-Za-z][A-Za-z0-9]*(?:_[A-Za-z0-9]+)+\Z")
|
||||
_UPPER_CODE = re.compile(r"(?<![A-Za-z0-9_])[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+(?![A-Za-z0-9_])")
|
||||
_SOURCE_ID = re.compile(r"([a-z][a-z0-9_]*)[::]([^\s,,;;:<>]+)\Z")
|
||||
_KNOWN_SOURCE_IN_TEXT = re.compile(r"(?<![A-Za-z0-9_])(" + "|".join(SOURCE_LABELS) + r")[::]([A-Za-z0-9]+)(?![A-Za-z0-9_])")
|
||||
|
||||
|
||||
def plain_text(value: Any) -> str:
|
||||
if value is None or value == "":
|
||||
return "—"
|
||||
if isinstance(value, bool):
|
||||
return "是" if value else "否"
|
||||
return str(value)
|
||||
|
||||
|
||||
def source_text(value: Any, fields: Mapping[str, str]) -> str:
|
||||
"""Localize a source prefix, preserving its entire numeric or opaque ID."""
|
||||
text = plain_text(value)
|
||||
if text in SOURCE_LABELS:
|
||||
return SOURCE_LABELS[text]
|
||||
if text.startswith("clinical."):
|
||||
field = text.removeprefix("clinical.")
|
||||
return "临床资料 · " + fields.get(field, "待核对项目")
|
||||
match = _SOURCE_ID.fullmatch(text)
|
||||
if match:
|
||||
prefix, identifier = match.groups()
|
||||
# Redaction manifests append a field name after the numeric source ID.
|
||||
if ":" in identifier:
|
||||
identifier, field = identifier.split(":", 1)
|
||||
return f"{SOURCE_LABELS.get(prefix, '其他来源')}(编号:{identifier}) · {fields.get(field, '待核对字段')}"
|
||||
return f"{SOURCE_LABELS.get(prefix, '其他来源')}(编号:{identifier})"
|
||||
if _MACHINE_KEY.fullmatch(text) or re.fullmatch(r"[A-Za-z][A-Za-z0-9_-]*", text):
|
||||
return "来源类型待核对"
|
||||
return _KNOWN_SOURCE_IN_TEXT.sub(lambda match: source_text(f"{match[1]}:{match[2]}", fields), text)
|
||||
|
||||
|
||||
def system_text(value: Any, labels: Mapping[str, str], fields: Mapping[str, str], *, strict: bool = False) -> str:
|
||||
"""Translate metadata, including historical ``CODE: source:id`` gap strings."""
|
||||
text = plain_text(value)
|
||||
if "\n" in text:
|
||||
return "\n".join(system_text(line, labels, fields, strict=strict) for line in text.split("\n"))
|
||||
if text in labels:
|
||||
return labels[text]
|
||||
if text in SOURCE_LABELS:
|
||||
return SOURCE_LABELS[text]
|
||||
if text in fields:
|
||||
return fields[text]
|
||||
# Only a technical prefix permits parsing the rest as a source identifier.
|
||||
compound = re.fullmatch(r"([A-Za-z][A-Za-z0-9_]+)\s*[::]\s*(.*)", text, re.DOTALL)
|
||||
if compound and (compound[1] in labels or _MACHINE_KEY.fullmatch(compound[1])):
|
||||
prefix = labels.get(compound[1], "未识别的系统原因,请联系管理员核对")
|
||||
return prefix + ":" + source_text(compound[2], fields)
|
||||
if _MACHINE_KEY.fullmatch(text):
|
||||
return "未识别的系统标识,请联系管理员核对"
|
||||
# Historic reports can include a known source/code inside a Chinese gap explanation.
|
||||
text = _UPPER_CODE.sub(lambda match: labels.get(match[0], "未识别的系统原因,请联系管理员核对"), text)
|
||||
text = _KNOWN_SOURCE_IN_TEXT.sub(lambda match: source_text(f"{match[1]}:{match[2]}", fields), text)
|
||||
if strict and re.fullmatch(r"[A-Za-z][A-Za-z0-9 ._-]*", text):
|
||||
return "未识别的系统状态,请联系管理员核对"
|
||||
return text
|
||||
|
||||
|
||||
def field_text(key: Any, fields: Mapping[str, str], labels: Mapping[str, str]) -> str:
|
||||
text = str(key)
|
||||
if text in fields:
|
||||
return fields[text]
|
||||
if text.endswith("_count") and text.removesuffix("_count") in SOURCE_LABELS:
|
||||
return SOURCE_LABELS[text.removesuffix("_count")] + "数"
|
||||
translated = system_text(text, labels, fields)
|
||||
if translated != text:
|
||||
return translated
|
||||
if text in SOURCE_LABELS or text.startswith("clinical.") or _SOURCE_ID.fullmatch(text):
|
||||
return source_text(text, fields)
|
||||
return "其他字段(待核对)" if re.search(r"[A-Za-z]", text) and not re.search(r"[\u4e00-\u9fff]", text) else text
|
||||
|
||||
|
||||
def value_text(value: Any, field: str, labels: Mapping[str, str], fields: Mapping[str, str]) -> str:
|
||||
if field in SOURCE_FIELDS:
|
||||
return source_text(value, fields)
|
||||
if field == "field":
|
||||
return field_text(value, fields, labels)
|
||||
if field == "coverage_status":
|
||||
return {"partial": "资料不全", "pending": "资料待核对", "unavailable": "暂无覆盖信息"}.get(str(value)) or system_text(value, labels, fields, strict=True)
|
||||
if field == "history_versioning" and value == "unavailable":
|
||||
return "历史版本无法核验"
|
||||
if field == "formula_type" and value == "auxiliary":
|
||||
return "辅方"
|
||||
if field.endswith("version") or field.endswith("versions"):
|
||||
text = plain_text(value)
|
||||
for prefix, name in (
|
||||
("manual-prescription-independent-v", "手动处方独立分析"),
|
||||
("manual-prescription-available-evidence-v", "手动处方已读资料分析"),
|
||||
("prescription-soft-dice-v", "处方药味剂量一致度算法"),
|
||||
("prescription-evidence-v", "处方证据资料格式"),
|
||||
("prescription-source-access-v", "处方来源权限格式"),
|
||||
):
|
||||
if text.startswith(prefix) and re.fullmatch(r"\d+(?:\.\d+)*", text.removeprefix(prefix)):
|
||||
return f"{name} · 第 {text.removeprefix(prefix)} 版"
|
||||
return text
|
||||
if field in ENUM_FIELDS:
|
||||
return system_text(value, labels, fields, strict=True)
|
||||
if field in REASON_FIELDS:
|
||||
return system_text(value, labels, fields, strict=field in {"code", "error_code", "reason_code"})
|
||||
if field.endswith(("_status", "_state", "_code")):
|
||||
return system_text(value, labels, fields, strict=True)
|
||||
if field and field not in fields:
|
||||
return system_text(value, labels, fields)
|
||||
return plain_text(value)
|
||||
@@ -0,0 +1,135 @@
|
||||
"""Honest presentation of server checkpoints, without fabricated totals or ETA."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
ACTIVE_STATES = {"pending", "preparing", "queued", "waiting", "waiting_sources", "waiting_transcript", "waiting_transcription", "running", "processing", "retrying", "retry_wait"}
|
||||
SUCCESS_STATES = {"succeeded", "completed", "success"}
|
||||
TERMINAL_STATES = SUCCESS_STATES | {"partial", "failed", "cancelled", "canceled", "blocked", "stale", "superseded", "invalid", "revoked", "deleted", "voided"}
|
||||
STAGES = {
|
||||
"preparing": "准备资料", "waiting_sources": "等待转写与资料", "queued": "排队等待处理",
|
||||
"text": "分析文字资料", "files": "分析附件", "reduce": "汇总资料要点",
|
||||
"final": "生成完整报告", "validating": "校验报告", "comparing": "计算用药对照",
|
||||
"completed": "已完成", "retry_wait": "等待重试", "failed": "处理失败", "cancelled": "已取消",
|
||||
"unknown": "等待阶段详情",
|
||||
}
|
||||
COMPACT_STAGES = {"preparing": "准备资料", "waiting_sources": "等待资料", "queued": "排队中", "text": "文字",
|
||||
"files": "附件", "reduce": "汇总", "final": "生成报告", "validating": "校验", "comparing": "用药对照",
|
||||
"completed": "已完成", "retry_wait": "待重试", "failed": "失败", "cancelled": "已取消", "unknown": "处理中"}
|
||||
STATUS_STAGE = {"pending": "queued", "waiting": "waiting_sources", "waiting_transcript": "waiting_sources",
|
||||
"waiting_transcription": "waiting_sources", "retrying": "retry_wait",
|
||||
**{state: "completed" for state in SUCCESS_STATES}, "canceled": "cancelled", "partial": "completed", "blocked": "failed"}
|
||||
|
||||
|
||||
def _mapping(value: Any) -> dict[str, Any]:
|
||||
return dict(value) if isinstance(value, Mapping) else {}
|
||||
|
||||
|
||||
def _integer(value: Any) -> int | None:
|
||||
# Counts/timestamps are integer contract fields, not arbitrary numeric text.
|
||||
return value if isinstance(value, int) and not isinstance(value, bool) and value >= 0 else None
|
||||
|
||||
|
||||
def duration(seconds: int) -> str:
|
||||
seconds = max(0, seconds)
|
||||
if seconds < 60:
|
||||
return f"{seconds} 秒"
|
||||
if seconds < 3600:
|
||||
return f"{seconds // 60} 分 {seconds % 60:02d} 秒"
|
||||
return f"{seconds // 3600} 小时 {seconds % 3600 // 60:02d} 分"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ProgressView:
|
||||
stage: str
|
||||
headline: str
|
||||
detail: str
|
||||
completed: int | None = None
|
||||
total: int | None = None
|
||||
busy: bool = False
|
||||
|
||||
|
||||
def progress_view(owner: Any, *, fallback_status: str = "", seconds: int = 0, live: bool = True) -> ProgressView:
|
||||
data = _mapping(owner)
|
||||
progress = _mapping(data.get("progress"))
|
||||
status = str(data.get("status") or fallback_status)
|
||||
stage = str(progress.get("stage") or STATUS_STAGE.get(status, status))
|
||||
if stage not in STAGES:
|
||||
stage = "unknown"
|
||||
terminal = status in TERMINAL_STATES
|
||||
if terminal:
|
||||
stage = STATUS_STAGE.get(status, status)
|
||||
if stage not in STAGES:
|
||||
stage = "unknown"
|
||||
active = status in ACTIVE_STATES and not terminal and stage not in {"completed", "failed", "cancelled"}
|
||||
advance = max(0, seconds) if active else 0
|
||||
headline = STAGES[stage]
|
||||
if status == "partial":
|
||||
headline = "部分模型已完成"
|
||||
if stage == "unknown":
|
||||
headline = "正在处理,等待阶段详情" if active else "暂无处理进度"
|
||||
completed = _integer(progress.get("completed_units"))
|
||||
total = _integer(progress.get("total_units"))
|
||||
if stage not in {"text", "files", "reduce"} or total is None or not 0 < total <= 1_000_000 or completed is None or completed > total:
|
||||
completed = total = None
|
||||
if total is not None:
|
||||
headline += f" · 本阶段 {completed}/{total} 组"
|
||||
|
||||
details = []
|
||||
attempt = _integer(progress.get("attempt"))
|
||||
if attempt is not None and 0 < attempt <= 1_000_000:
|
||||
details.append(f"第 {attempt} 次尝试")
|
||||
elapsed = _integer(progress.get("elapsed_seconds"))
|
||||
stage_elapsed = _integer(progress.get("stage_elapsed_seconds"))
|
||||
if elapsed is not None:
|
||||
# Retry metadata freezes the previous attempt's duration. Only its
|
||||
# scheduling countdown and update age continue between server polls.
|
||||
details.append("已用时 " + duration(elapsed + (0 if stage == "retry_wait" else advance)))
|
||||
if stage_elapsed is not None and active and stage != "retry_wait":
|
||||
details.append("本阶段 " + duration(stage_elapsed + advance))
|
||||
remaining = _integer(progress.get("wait_remaining_seconds"))
|
||||
if stage in {"preparing", "waiting_sources", "retry_wait"} and remaining is not None and active:
|
||||
remaining = max(0, remaining - advance)
|
||||
details.append("资料等待窗口剩余 " + duration(remaining) if remaining else "等待窗口已到,等待服务端确认")
|
||||
if stage == "retry_wait":
|
||||
details[-1] = "距下次重试 " + duration(remaining) if remaining else "重试时间已到,等待服务端确认"
|
||||
server_time = _integer(progress.get("server_time"))
|
||||
updated_at = _integer(progress.get("updated_at"))
|
||||
if active and server_time is not None and updated_at is not None and updated_at > 0:
|
||||
details.append("阶段更新于 " + duration(max(0, server_time - updated_at) + advance) + "前")
|
||||
if not progress and active:
|
||||
details.append("服务端暂未提供分阶段进度")
|
||||
notice = progress.get("notice")
|
||||
terminal_notice = stage in {"failed", "cancelled"} and progress.get("stage") == stage and progress.get("phase") == "failed"
|
||||
if isinstance(notice, str) and notice.strip() and (not terminal or terminal_notice):
|
||||
details.append(notice.strip())
|
||||
elif stage in {"final", "text", "files", "reduce"} and active:
|
||||
details.append("等待模型响应;耗时取决于资料量与模型服务")
|
||||
return ProgressView(stage, headline, " · ".join(details), completed, total, live and active)
|
||||
|
||||
|
||||
def flow_text(batch: Any) -> str:
|
||||
data = _mapping(batch)
|
||||
status = data.get("status")
|
||||
if not data:
|
||||
return "准备资料 → 双模型分析 → 用药对照 → 完成"
|
||||
if data.get("validity") not in (None, "", "current", "valid"):
|
||||
return "此批次已失效 · 以下为最后保存的处理记录"
|
||||
models = [_mapping(_mapping(data.get("models")).get(key)) for key in ("qwen", "openai")]
|
||||
complete = sum(model.get("status") in SUCCESS_STATES for model in models)
|
||||
failed = sum(model.get("status") == "failed" for model in models)
|
||||
stages = [progress_view(model).stage for model in models]
|
||||
batch_stage = progress_view(data).stage
|
||||
if status in {"failed", "cancelled", "canceled", "blocked"}:
|
||||
return f"处理已停止 · {complete}/2 个模型完成" + (f" · {failed} 个模型失败" if failed else "")
|
||||
if batch_stage in {"preparing", "waiting_sources"}:
|
||||
return "准备资料:进行中 → 双模型分析:待开始 → 用药对照:待开始 → 完成:待处理"
|
||||
prepared = "已完成" if any(models) else "待确认"
|
||||
comparisons = sum(model.get("status") in SUCCESS_STATES and bool(model.get("comparison")) for model in models)
|
||||
compare_state = f"{comparisons}/2 已处理" if comparisons else "进行中" if "comparing" in stages else "待处理"
|
||||
analysis = f"{complete}/2 完成" + (f",{failed} 个失败" if failed else ",进行中" if status not in TERMINAL_STATES else "")
|
||||
end = "已完成" if complete == 2 else "部分完成" if status == "partial" else "待处理"
|
||||
return f"准备资料:{prepared} → 双模型分析:{analysis} → 用药对照:{compare_state} → 完成:{end}"
|
||||
@@ -20,6 +20,7 @@ from datetime import date
|
||||
from pathlib import Path
|
||||
from time import monotonic
|
||||
from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
from PySide6.QtCore import (
|
||||
QBuffer,
|
||||
@@ -2658,6 +2659,8 @@ class PrescriptionEditorDialog(QDialog):
|
||||
else None
|
||||
)
|
||||
self._source = _mapping(prescription)
|
||||
self._save_fingerprint = ""
|
||||
self._save_request_key = ""
|
||||
self._loading_data = False
|
||||
self._linked_order_generation = 0
|
||||
self._diagnosis_view: _StructuredDiagnosisDialog | None = None
|
||||
@@ -3786,6 +3789,7 @@ class PrescriptionEditorDialog(QDialog):
|
||||
"audit_remark",
|
||||
"business_prescription_audit_rejected",
|
||||
"business_prescription_audit_remark",
|
||||
"ai_assisted",
|
||||
)
|
||||
result = {key: self._source.get(key) for key in hidden_keys if key in self._source}
|
||||
if self.mode == "add":
|
||||
@@ -3838,6 +3842,20 @@ class PrescriptionEditorDialog(QDialog):
|
||||
result["dosage_amount"] = dosage_amount
|
||||
else:
|
||||
result.pop("dosage_amount", None)
|
||||
# This editor has no independent-assistance attestation control. Only
|
||||
# retain positive evidence of AI exposure; a seed's false is not a new
|
||||
# doctor-confirmed statement that this submission was unassisted.
|
||||
if result.get("ai_assisted") in (True, 1, "1", "true"):
|
||||
result["ai_assisted"] = True
|
||||
else:
|
||||
result.pop("ai_assisted", None)
|
||||
# A repeated submit of unchanged editor content keeps its idempotency key.
|
||||
# Unknown AI exposure is omitted, rather than falsely asserted as False.
|
||||
fingerprint = json.dumps(result, ensure_ascii=False, sort_keys=True, default=str)
|
||||
if fingerprint != self._save_fingerprint:
|
||||
self._save_fingerprint = fingerprint
|
||||
self._save_request_key = str(uuid4())
|
||||
result["request_key"] = self._save_request_key
|
||||
return result
|
||||
|
||||
def _herb_validation_label(self, global_index: int) -> str:
|
||||
|
||||
@@ -8,7 +8,7 @@ from html import escape
|
||||
from math import ceil
|
||||
from typing import Any
|
||||
|
||||
from PySide6.QtCore import QDateTime, QModelIndex, QRectF, QSize, Qt
|
||||
from PySide6.QtCore import QDateTime, QEvent, QModelIndex, QRectF, QSize, Qt, QTimer
|
||||
from PySide6.QtGui import (
|
||||
QColor,
|
||||
QFont,
|
||||
@@ -33,7 +33,8 @@ from PySide6.QtWidgets import (
|
||||
QLabel,
|
||||
QLineEdit,
|
||||
QListWidget,
|
||||
QListWidgetItem,
|
||||
QListWidgetItem,
|
||||
QMenu,
|
||||
QMessageBox,
|
||||
QPushButton,
|
||||
QScrollArea,
|
||||
@@ -48,7 +49,16 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from .. import icons, motion
|
||||
from .. import icons, motion
|
||||
from ..dialogs.issued_prescription_ai import (
|
||||
PrescriptionAiStatisticsDialog,
|
||||
agreement_text,
|
||||
batch_running,
|
||||
can_open_issued_ai,
|
||||
present_issued_prescription_ai,
|
||||
state_text,
|
||||
status_tooltip,
|
||||
)
|
||||
from ..dialogs.prescription import (
|
||||
AuditPrescriptionDialog,
|
||||
DiagnosisDetailDialog,
|
||||
@@ -435,7 +445,22 @@ def _formula(value: Any) -> str:
|
||||
return "辅方" if text in {"2", "aux", "auxiliary", "辅方"} else "主方"
|
||||
|
||||
|
||||
def _order_warnings(row: Any) -> list[str]:
|
||||
def _is_blank_prescription(row: Any) -> bool:
|
||||
if row is None or _truthy(get_value(row, "is_system_auto")):
|
||||
return True
|
||||
raw = getattr(row, "raw", None)
|
||||
source = raw if isinstance(raw, Mapping) and raw else row
|
||||
missing = object()
|
||||
herbs = get_value(source, "herbs", missing)
|
||||
# Compact historical rows may omit herbs; omission is not an empty prescription.
|
||||
if herbs is missing:
|
||||
return False
|
||||
return not isinstance(herbs, (list, tuple)) or not any(
|
||||
str(get_value(herb, "name", "") or "").strip() for herb in herbs
|
||||
)
|
||||
|
||||
|
||||
def _order_warnings(row: Any) -> list[str]:
|
||||
"""Match the PC list's linked-order checks, including blank herb rows."""
|
||||
|
||||
raw = getattr(row, "raw", None)
|
||||
@@ -877,7 +902,7 @@ class _PrescriptionInfoDelegate(QStyledItemDelegate):
|
||||
painter.setPen(QColor(foreground))
|
||||
painter.drawText(pill, Qt.AlignmentFlag.AlignCenter, label)
|
||||
elif column != 2:
|
||||
lines = text.rsplit(" · ", 2) if column == 5 else text.rsplit(" ", 1) if column == 10 else [text]
|
||||
lines = text.rsplit(" · ", 2) if column == 5 else text.rsplit(" ", 1) if column == 10 else text.splitlines() if column == 12 else [text]
|
||||
if len(lines) > 1:
|
||||
primary, secondary = lines[0], " · ".join(lines[1:]) if column == 5 else lines[1]
|
||||
if column == 5:
|
||||
@@ -979,7 +1004,18 @@ class PrescriptionsPage(QWidget):
|
||||
self._detail_target = 0
|
||||
self._diagnosis_detail_generation = 0
|
||||
self._diagnosis_detail_target = 0
|
||||
self._mutation_pending = False
|
||||
self._mutation_pending = False
|
||||
self._ai_statuses: dict[int, dict[str, Any]] = {}
|
||||
self._ai_enabled = False
|
||||
self._ai_request_token = 0
|
||||
self._ai_pending = False
|
||||
self._ai_timer = QTimer(self)
|
||||
self._ai_timer.setInterval(5000)
|
||||
self._ai_timer.timeout.connect(self._load_ai_statuses)
|
||||
self._ai_scroll_timer = QTimer(self)
|
||||
self._ai_scroll_timer.setSingleShot(True)
|
||||
self._ai_scroll_timer.setInterval(180)
|
||||
self._ai_scroll_timer.timeout.connect(self._load_ai_statuses)
|
||||
|
||||
outer = QVBoxLayout(self)
|
||||
outer.setContentsMargins(28, 16, 26, 8)
|
||||
@@ -1010,7 +1046,11 @@ class PrescriptionsPage(QWidget):
|
||||
self.orders_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.orders_button.setVisible(has_permission(permissions, "tcm.prescriptionOrder/lists"))
|
||||
self.orders_button.clicked.connect(lambda: self._open_orders())
|
||||
header.add_action(self.orders_button)
|
||||
header.add_action(self.orders_button)
|
||||
self.ai_statistics_button = QPushButton("AI 一致度统计", header)
|
||||
self.ai_statistics_button.setVisible(has_permission(permissions, "tcm.prescriptionAi/statistics", default=False) and callable(getattr(repository, "prescription_ai_statistics", None)))
|
||||
self.ai_statistics_button.clicked.connect(self._open_ai_statistics)
|
||||
header.add_action(self.ai_statistics_button)
|
||||
self.add_button = QPushButton("新增处方", header)
|
||||
self.add_button.setObjectName("PrescriptionAddButton")
|
||||
self.add_button.setMinimumWidth(122)
|
||||
@@ -1156,7 +1196,10 @@ class PrescriptionsPage(QWidget):
|
||||
toolbar.addWidget(self.count_badge)
|
||||
toolbar.addStretch(1)
|
||||
self.view_button = self._action_button("查看", "cf.prescription/read", self._view_selected)
|
||||
toolbar.addWidget(self.view_button)
|
||||
toolbar.addWidget(self.view_button)
|
||||
self.ai_report_button = self._action_button("AI 报告", "tcm.prescriptionAi/reports", self._open_ai_report)
|
||||
self.ai_report_button.hide()
|
||||
toolbar.addWidget(self.ai_report_button)
|
||||
self.patch_button = self._action_button(
|
||||
"修改患者", "tcm.prescription/patchPatient", self._patch_selected
|
||||
)
|
||||
@@ -1181,9 +1224,17 @@ class PrescriptionsPage(QWidget):
|
||||
refresh.setIcon(_blue_prescription_icon("refresh", "#5D6B80"))
|
||||
refresh.setIconSize(QSize(15, 15))
|
||||
refresh.clicked.connect(self.refresh)
|
||||
toolbar.addWidget(refresh)
|
||||
layout.addWidget(toolbar_scroll)
|
||||
self.stack = QStackedWidget()
|
||||
toolbar.addWidget(refresh)
|
||||
layout.addWidget(toolbar_scroll)
|
||||
self.ai_status_notice = QLabel("AI 分析:正在检查服务状态。", card)
|
||||
self.ai_status_notice.setObjectName("PrescriptionAiStatusNotice")
|
||||
self.ai_status_notice.setProperty("role", "muted")
|
||||
self.ai_status_notice.setTextFormat(Qt.TextFormat.PlainText)
|
||||
self.ai_status_notice.setWordWrap(True)
|
||||
self.ai_status_notice.setMargin(12)
|
||||
self.ai_status_notice.setAccessibleName("AI 分析状态")
|
||||
layout.addWidget(self.ai_status_notice)
|
||||
self.stack = QStackedWidget()
|
||||
table_host = QWidget()
|
||||
table_layout = QVBoxLayout(table_host)
|
||||
table_layout.setContentsMargins(0, 0, 0, 0)
|
||||
@@ -1200,7 +1251,9 @@ class PrescriptionsPage(QWidget):
|
||||
TableColumn("void_status", "作废", 72, _void_cell),
|
||||
TableColumn("doctor_name", "医生信息", 180, _doctor_cell),
|
||||
TableColumn("assistant_name", "医助", 125),
|
||||
TableColumn("create_time", "创建时间", 180, _create_time_cell),
|
||||
TableColumn("create_time", "创建时间", 180, _create_time_cell),
|
||||
TableColumn("__ai_status__", "AI 分析", 144, lambda _value, _row: "—"),
|
||||
TableColumn("__ai_agreement__", "与 AI 一致度", 130, lambda _value, _row: "—"),
|
||||
]
|
||||
)
|
||||
self.table.setObjectName("PrescriptionTable")
|
||||
@@ -1213,8 +1266,13 @@ class PrescriptionsPage(QWidget):
|
||||
self.table.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
|
||||
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Interactive)
|
||||
self.table.horizontalHeader().moveSection(2, 10)
|
||||
for column, width in enumerate((42, 192, 144, 108, 94, 144, 108, 80, 137, 83, 128)):
|
||||
self.table.setColumnWidth(column, width)
|
||||
for column, width in enumerate((42, 192, 144, 108, 94, 144, 108, 80, 137, 83, 128)):
|
||||
self.table.setColumnWidth(column, width)
|
||||
self.table.setColumnHidden(11, True)
|
||||
self.table.setColumnHidden(12, True)
|
||||
self.table.horizontalHeaderItem(12).setToolTip("分别显示千问、OpenAI 的药味与剂量一致度;点击查看逐味贡献。")
|
||||
self.table.horizontalHeader().viewport().installEventFilter(self)
|
||||
self.table.verticalScrollBar().valueChanged.connect(lambda _value: self._schedule_ai_statuses())
|
||||
self.table.setWordWrap(False)
|
||||
# Rows are not uniform: the number column's delegate grows a row that
|
||||
# carries an order warning so the warning text stays readable without a
|
||||
@@ -1227,7 +1285,10 @@ class PrescriptionsPage(QWidget):
|
||||
self.table.horizontalHeaderItem(0).setIcon(_blue_prescription_icon("checkbox", "#8A97A9", 14))
|
||||
self.table.horizontalHeaderItem(0).setTextAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self.table.itemSelectionChanged.connect(self._selection_changed)
|
||||
self.table.itemDoubleClicked.connect(lambda _item: self._view_selected())
|
||||
self.table.itemDoubleClicked.connect(lambda _item: self._view_selected())
|
||||
self.table.itemClicked.connect(lambda item: self._open_ai_report() if item.column() in {11, 12} else None)
|
||||
self.table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||
self.table.customContextMenuRequested.connect(self._open_ai_context_menu)
|
||||
table_layout.addWidget(self.table, 1)
|
||||
self.pager = InfiniteList(self._page_size)
|
||||
self.pager.bind(self.table)
|
||||
@@ -1271,9 +1332,22 @@ class PrescriptionsPage(QWidget):
|
||||
self.filter_grid.setColumnStretch(column, stretch)
|
||||
self.filter_card.setFixedHeight(200 if compact else 144)
|
||||
|
||||
def _number_column_resized(self, column: int, _old_size: int, _new_size: int) -> None:
|
||||
def _number_column_resized(self, column: int, _old_size: int, _new_size: int) -> None:
|
||||
if column == 1:
|
||||
self.table.resizeRowsToContents()
|
||||
self.table.resizeRowsToContents()
|
||||
|
||||
def eventFilter(self, watched: Any, event: Any) -> bool:
|
||||
if hasattr(self, "table") and watched is self.table.horizontalHeader().viewport() and event.type() in {QEvent.Type.MouseButtonPress, QEvent.Type.MouseButtonRelease, QEvent.Type.MouseButtonDblClick}:
|
||||
header = self.table.horizontalHeader()
|
||||
position = event.position().toPoint()
|
||||
column = header.logicalIndexAt(position)
|
||||
if column in {11, 12} and event.button() == Qt.MouseButton.LeftButton:
|
||||
relative = position.x() - header.sectionViewportPosition(column)
|
||||
# Keep native column resizing, but never rank mixed-model display
|
||||
# text or treat unavailable values as numeric zero through sorting.
|
||||
if 5 < relative < header.sectionSize(column) - 5:
|
||||
return True
|
||||
return super().eventFilter(watched, event)
|
||||
|
||||
def _action_button(
|
||||
self,
|
||||
@@ -1354,7 +1428,11 @@ class PrescriptionsPage(QWidget):
|
||||
self.doctor_filter.clear()
|
||||
self._search()
|
||||
|
||||
def refresh(self) -> None:
|
||||
def refresh(self) -> None:
|
||||
self._ai_timer.stop()
|
||||
self._ai_request_token += 1
|
||||
self._ai_pending = False
|
||||
self._ai_statuses.clear()
|
||||
self._loading = True
|
||||
self._refresh_pending = False
|
||||
self._generation += 1
|
||||
@@ -1392,8 +1470,9 @@ class PrescriptionsPage(QWidget):
|
||||
if generation != self._generation:
|
||||
return
|
||||
rows = page_items(result)
|
||||
self.table.set_rows(rows)
|
||||
self._decorate_rows()
|
||||
self.table.set_rows(rows)
|
||||
self._decorate_rows()
|
||||
self._render_ai_statuses()
|
||||
total = page_total(result, len(rows))
|
||||
self.pager.update_state(requested_page, total)
|
||||
self.count_badge.setText(f"共 {total} 条")
|
||||
@@ -1415,7 +1494,8 @@ class PrescriptionsPage(QWidget):
|
||||
self.banner.clear()
|
||||
if rows and self.table.currentRow() < 0:
|
||||
self.table.selectRow(0)
|
||||
self._selection_changed()
|
||||
self._selection_changed()
|
||||
self._load_ai_statuses()
|
||||
|
||||
def _decorate_rows(self) -> None:
|
||||
"""Apply the reference table's tags, checkbox, avatar, and row actions."""
|
||||
@@ -1489,7 +1569,7 @@ class PrescriptionsPage(QWidget):
|
||||
actions.setContentsMargins(3, 0, 3, 0)
|
||||
actions.setSpacing(3)
|
||||
actions.addStretch(1)
|
||||
if has_permission(self.permissions, "cf.prescription/read"):
|
||||
if has_permission(self.permissions, "cf.prescription/read"):
|
||||
actions.addWidget(
|
||||
_row_action_button(
|
||||
"eye",
|
||||
@@ -1499,7 +1579,15 @@ class PrescriptionsPage(QWidget):
|
||||
),
|
||||
actions_host,
|
||||
)
|
||||
)
|
||||
)
|
||||
if self._ai_enabled and can_open_issued_ai(self.permissions) and not _is_blank_prescription(row):
|
||||
actions.addWidget(
|
||||
_row_action_button(
|
||||
"eye", "AI 报告",
|
||||
lambda _checked=False, target=row: self._run_row_action(target, self._open_ai_report),
|
||||
actions_host, label="AI",
|
||||
)
|
||||
)
|
||||
if has_permission(self.permissions, "cf.prescription/edit"):
|
||||
actions.addWidget(
|
||||
_row_action_button(
|
||||
@@ -1531,7 +1619,179 @@ class PrescriptionsPage(QWidget):
|
||||
actions.addStretch(1)
|
||||
self.table.setCellWidget(row_index, 2, actions_host)
|
||||
self._sync_row_mutation_actions()
|
||||
self.table.resizeRowsToContents()
|
||||
self.table.resizeRowsToContents()
|
||||
|
||||
def _visible_ai_ids(self) -> list[int]:
|
||||
if not self.isVisible() or not self.table.isVisible():
|
||||
return []
|
||||
ids = []
|
||||
viewport = self.table.viewport().rect()
|
||||
for index in range(self.table.rowCount()):
|
||||
item = self.table.item(index, 0)
|
||||
# Column 0 may be horizontally off-screen; use row geometry only.
|
||||
top = self.table.rowViewportPosition(index)
|
||||
if item is None or top + self.table.rowHeight(index) <= 0 or top >= viewport.height():
|
||||
continue
|
||||
row = item.data(Qt.ItemDataRole.UserRole)
|
||||
if _is_blank_prescription(row):
|
||||
continue
|
||||
value = _int(first_value(row, "id", "prescription_id"), 0)
|
||||
if value > 0:
|
||||
ids.append(value)
|
||||
return list(dict.fromkeys(ids))[:100]
|
||||
|
||||
def _schedule_ai_statuses(self) -> None:
|
||||
if self.isVisible():
|
||||
self._ai_scroll_timer.start()
|
||||
|
||||
def _load_ai_statuses(self) -> None:
|
||||
only_blank = self.table.rowCount() > 0 and all(
|
||||
_is_blank_prescription(self.table.item(index, 0).data(Qt.ItemDataRole.UserRole))
|
||||
for index in range(self.table.rowCount())
|
||||
)
|
||||
self.ai_status_notice.setVisible(not only_blank)
|
||||
if only_blank:
|
||||
self._ai_timer.stop()
|
||||
self._set_ai_columns(False)
|
||||
return
|
||||
method = getattr(self.repository, "list_prescription_ai_statuses", None)
|
||||
if not has_permission(self.permissions, "tcm.prescriptionAi/statuses", default=False):
|
||||
self.ai_status_notice.setText("AI 分析:当前账号没有查看分析状态的权限,请联系管理员授权。")
|
||||
return
|
||||
if not callable(method):
|
||||
self.ai_status_notice.setText("AI 分析:当前数据模式暂不支持此功能。")
|
||||
return
|
||||
if self._ai_pending:
|
||||
return
|
||||
ids = self._visible_ai_ids()
|
||||
ids = [value for value in ids if value not in self._ai_statuses or batch_running(self._ai_statuses[value])]
|
||||
if not ids:
|
||||
self._ai_timer.stop()
|
||||
if self.table.rowCount() == 0:
|
||||
self.ai_status_notice.setText("AI 分析:当前列表没有处方,暂无可查看的分析结果。")
|
||||
return
|
||||
self._ai_pending = True
|
||||
self._ai_request_token += 1
|
||||
token, generation = self._ai_request_token, self._generation
|
||||
run_async(
|
||||
lambda: method(ids),
|
||||
on_success=lambda result: self._ai_statuses_ready(result, ids, token, generation),
|
||||
on_error=lambda error: self._ai_statuses_error(error, token, generation),
|
||||
on_finished=lambda: self._ai_statuses_finished(token),
|
||||
)
|
||||
|
||||
def _ai_statuses_finished(self, token: int) -> None:
|
||||
if token == self._ai_request_token:
|
||||
self._ai_pending = False
|
||||
|
||||
def _set_ai_columns(self, enabled: bool) -> None:
|
||||
changed = enabled != self._ai_enabled
|
||||
self._ai_enabled = enabled
|
||||
for column in (11, 12):
|
||||
self.table.setColumnHidden(column, not enabled)
|
||||
if enabled:
|
||||
header = self.table.horizontalHeader()
|
||||
header.moveSection(header.visualIndex(11), header.visualIndex(4) + 1)
|
||||
header.moveSection(header.visualIndex(12), header.visualIndex(11) + 1)
|
||||
self.table.setColumnWidth(11, 144)
|
||||
self.table.setColumnWidth(12, 130)
|
||||
self.table.setColumnWidth(2, 178)
|
||||
if changed:
|
||||
self._decorate_rows()
|
||||
|
||||
def _ai_statuses_ready(self, result: Any, ids: list[int], token: int, generation: int) -> None:
|
||||
if token != self._ai_request_token or generation != self._generation or not self.isVisible():
|
||||
return
|
||||
data = _row_mapping(result)
|
||||
self._set_ai_columns(data.get("enabled") is True)
|
||||
if not self._ai_enabled:
|
||||
self._ai_timer.stop()
|
||||
notice = "AI 分析未启用:暂不生成报告或一致度,请联系管理员启用。"
|
||||
if can_open_issued_ai(self.permissions):
|
||||
notice += "已有报告仍可从“AI 报告”查看。"
|
||||
self.ai_status_notice.setText(notice)
|
||||
self.ai_status_notice.setToolTip("")
|
||||
self.ai_report_button.setToolTip("自动分析未启用;仍可查看已保存的历史报告。")
|
||||
return
|
||||
self.ai_status_notice.setText("AI 分析已启用:保存手工处方后自动生成两份报告,并显示药味与剂量一致度。")
|
||||
self.ai_status_notice.setToolTip("")
|
||||
self.ai_report_button.setToolTip("查看两份 AI 报告、候选处方和逐味对照。")
|
||||
for value in ids:
|
||||
self._ai_statuses[value] = {}
|
||||
for batch in data.get("items") or []:
|
||||
value = _int(get_value(batch, "prescription_id"), 0)
|
||||
if value in ids:
|
||||
self._ai_statuses[value] = _row_mapping(batch)
|
||||
self._render_ai_statuses()
|
||||
if any(batch_running(self._ai_statuses.get(value)) for value in self._visible_ai_ids()):
|
||||
self._ai_timer.start()
|
||||
else:
|
||||
self._ai_timer.stop()
|
||||
|
||||
def _render_ai_statuses(self) -> None:
|
||||
sorting = self.table.isSortingEnabled()
|
||||
self.table.setSortingEnabled(False)
|
||||
changed = False
|
||||
try:
|
||||
for index in range(self.table.rowCount()):
|
||||
row = self.table.item(index, 0).data(Qt.ItemDataRole.UserRole)
|
||||
value = _int(first_value(row, "id", "prescription_id"), 0)
|
||||
batch = self._ai_statuses.get(value)
|
||||
blank = _is_blank_prescription(row)
|
||||
if batch is None and not blank:
|
||||
continue
|
||||
state = "" if blank else (state_text(batch) if batch else "尚无分析记录")
|
||||
agreement = "" if blank else agreement_text(batch)
|
||||
for column, text in ((11, state), (12, agreement)):
|
||||
item = self.table.item(index, column)
|
||||
if item.text() != text:
|
||||
item.setText(text)
|
||||
changed = True
|
||||
item.setToolTip("" if blank else status_tooltip(batch))
|
||||
item.setData(Qt.ItemDataRole.AccessibleTextRole, text)
|
||||
if changed:
|
||||
self.table.resizeRowsToContents()
|
||||
finally:
|
||||
self.table.setSortingEnabled(sorting)
|
||||
|
||||
def _ai_statuses_error(self, error: Exception, token: int, generation: int) -> None:
|
||||
if token == self._ai_request_token and generation == self._generation:
|
||||
self._ai_timer.stop()
|
||||
self._set_ai_columns(False)
|
||||
self.ai_status_notice.setText("AI 分析暂不可用:请稍后刷新;持续无法使用时,请联系管理员检查服务。")
|
||||
self.ai_status_notice.setToolTip(friendly_error(error))
|
||||
self.ai_report_button.setToolTip("AI 状态暂不可用:" + friendly_error(error))
|
||||
|
||||
def _open_ai_report(self) -> None:
|
||||
row = self._selected()
|
||||
if _is_blank_prescription(row):
|
||||
return
|
||||
value = _int(first_value(row, "id", "prescription_id"), 0)
|
||||
if value > 0:
|
||||
present_issued_prescription_ai(self.repository, self.permissions, self, prescription_id=value)
|
||||
|
||||
def _open_ai_context_menu(self, position: Any) -> None:
|
||||
if not can_open_issued_ai(self.permissions) or not callable(getattr(self.repository, "list_prescription_ai_reports", None)):
|
||||
return
|
||||
item = self.table.itemAt(position)
|
||||
if item is None:
|
||||
return
|
||||
self.table.selectRow(item.row())
|
||||
row = self._selected()
|
||||
if _is_blank_prescription(row):
|
||||
return
|
||||
menu = QMenu(self.table)
|
||||
action = menu.addAction("AI 报告 / 逐味对照")
|
||||
action.triggered.connect(lambda: self._run_row_action(row, self._open_ai_report))
|
||||
self._ai_context_menu = menu
|
||||
menu.popup(self.table.viewport().mapToGlobal(position))
|
||||
|
||||
def _open_ai_statistics(self) -> None:
|
||||
if not has_permission(self.permissions, "tcm.prescriptionAi/statistics", default=False):
|
||||
return
|
||||
dialog = PrescriptionAiStatisticsDialog(self.repository, self.permissions, self)
|
||||
dialog.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, True)
|
||||
dialog.show()
|
||||
|
||||
def _run_row_action(self, row: Any, callback: Callable[[], None]) -> None:
|
||||
target_id = _int(first_value(row, "id", "prescription_id", default=None), 0)
|
||||
@@ -1566,7 +1826,14 @@ class PrescriptionsPage(QWidget):
|
||||
def _selection_changed(self) -> None:
|
||||
row = self.table.current_data()
|
||||
active = not self._mutation_pending
|
||||
self.view_button.setEnabled(active and row is not None)
|
||||
self.view_button.setEnabled(active and row is not None)
|
||||
ai_available = (
|
||||
not _is_blank_prescription(row)
|
||||
and can_open_issued_ai(self.permissions)
|
||||
and callable(getattr(self.repository, "list_prescription_ai_reports", None))
|
||||
)
|
||||
self.ai_report_button.setVisible(ai_available)
|
||||
self.ai_report_button.setEnabled(ai_available)
|
||||
self.patch_button.setEnabled(active and can_patch_patient(row))
|
||||
self.create_order_button.setEnabled(active and can_create_order(row))
|
||||
self.edit_button.setEnabled(active and can_edit_or_delete(row))
|
||||
@@ -1935,10 +2202,19 @@ class PrescriptionsPage(QWidget):
|
||||
self.banner.show_message(message, "danger")
|
||||
show_toast(self, message, "danger", 5000)
|
||||
|
||||
def showEvent(self, event: Any) -> None:
|
||||
def showEvent(self, event: Any) -> None:
|
||||
super().showEvent(event)
|
||||
if self.table.rowCount() == 0 and not self._loading:
|
||||
self.refresh()
|
||||
if self.table.rowCount() == 0 and not self._loading:
|
||||
self.refresh()
|
||||
elif not self._loading:
|
||||
self._load_ai_statuses()
|
||||
|
||||
def hideEvent(self, event: Any) -> None:
|
||||
self._ai_timer.stop()
|
||||
self._ai_scroll_timer.stop()
|
||||
self._ai_request_token += 1
|
||||
self._ai_pending = False
|
||||
super().hideEvent(event)
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
||||
@@ -127,6 +127,13 @@ def format_record_time(value: Any, default: str = "—") -> str:
|
||||
raw = str(value).strip()
|
||||
if not raw:
|
||||
return default
|
||||
# The API sends 0 for "not set yet" (a snapshot cutoff that has not been frozen, an
|
||||
# unfinished task); rendering it as a bare 0 or as 1970 would read as a real time.
|
||||
try:
|
||||
if float(raw) <= 0:
|
||||
return default
|
||||
except ValueError:
|
||||
pass
|
||||
if _UNIX_TIMESTAMP_RE.fullmatch(raw):
|
||||
stamp = float(raw)
|
||||
if stamp >= 10_000_000_000:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -303,7 +303,8 @@ def test_issued_page_sends_exact_filter_dto_and_row_guards(
|
||||
page.table.selectRow(0)
|
||||
page._selection_changed()
|
||||
|
||||
assert page.table.columnCount() == 11
|
||||
assert page.table.columnCount() == 13
|
||||
assert page.table.isColumnHidden(11) and page.table.isColumnHidden(12)
|
||||
assert page.table.horizontalHeaderItem(2).text() == "操作"
|
||||
assert page.table.cellWidget(0, 2) is not None
|
||||
# 处方类型与审核状态由 _RowDecorationDelegate 绘制标签,不再为每行每列
|
||||
|
||||
@@ -121,7 +121,8 @@ def test_shell_preserves_all_columns_filters_and_reachable_pager(
|
||||
table = page.table
|
||||
assert [column.key for column in table.columns] == [
|
||||
"__selected__", "sn", "__actions__", "prescription_type", "is_system_auto",
|
||||
"patient_name", "audit_status", "void_status", "doctor_name", "assistant_name", "create_time",
|
||||
"patient_name", "audit_status", "void_status", "doctor_name", "assistant_name", "create_time",
|
||||
"__ai_status__", "__ai_agreement__",
|
||||
]
|
||||
assert [table.horizontalHeader().logicalIndex(index) for index in range(11)] == [
|
||||
0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 2,
|
||||
|
||||
@@ -46,6 +46,15 @@ def test_format_record_time_with_datetime_returns_minute_precision() -> None:
|
||||
assert format_record_time(date(2026, 8, 20)) == "2026-08-20"
|
||||
|
||||
|
||||
def test_format_record_time_with_unset_epoch_returns_default() -> None:
|
||||
# The API sends 0 (and occasionally "0") for a snapshot cutoff or finish time that does
|
||||
# not exist yet; it must not be rendered as a bare 0 or as 1970.
|
||||
assert format_record_time(0) == "—"
|
||||
assert format_record_time("0") == "—"
|
||||
assert format_record_time(-1) == "—"
|
||||
assert format_record_time(0, default="未开始") == "未开始"
|
||||
|
||||
|
||||
def test_format_record_time_with_garbage_returns_raw_value() -> None:
|
||||
assert format_record_time("not-a-timestamp") == "not-a-timestamp"
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
// Local-only additive schema upgrade. Never prints connection secrets or patient content.
|
||||
$root = dirname(__DIR__, 2) . '/server/';
|
||||
chdir($root);
|
||||
require $root . 'vendor/autoload.php';
|
||||
$app = new \think\App($root);
|
||||
$app->initialize();
|
||||
use think\facade\Db;
|
||||
try {
|
||||
$connection = (string) config('database.default');
|
||||
$cfg = (array) config('database.connections.' . $connection);
|
||||
if (!in_array((string) ($cfg['hostname'] ?? ''), ['127.0.0.1', 'localhost', '::1'], true)
|
||||
|| ($cfg['prefix'] ?? '') !== 'zyt_') {
|
||||
throw new RuntimeException('Local database/prefix guard rejected');
|
||||
}
|
||||
$active = Db::name('prescription_ai_task')->whereIn('status', ['queued', 'running', 'retry_wait'])->count()
|
||||
+ Db::name('prescription_ai_batch')->where('validity', 'current')->whereIn('status', ['preparing', 'waiting_sources', 'queued', 'running', 'retry_wait'])->count();
|
||||
if ($active > 0) { throw new RuntimeException('Tasks must finish before this local upgrade'); }
|
||||
$snapshot = static function (): array {
|
||||
return [
|
||||
'batches' => Db::name('prescription_ai_batch')->count(),
|
||||
'results' => Db::name('prescription_ai_result')->count(),
|
||||
'attempts' => Db::name('prescription_ai_attempt')->count(),
|
||||
'tasks_hash' => hash('sha256', json_encode(Db::name('prescription_ai_task')->field('id,status,attempts,total_attempts,manual_retries,result_id')->order('id')->select()->toArray())),
|
||||
];
|
||||
};
|
||||
$before = $snapshot();
|
||||
$present = isset(Db::name('prescription_ai_task')->getFields()['progress_json']);
|
||||
$sqlFile = $root . 'database/migrations/2026_09_10_prescription_ai_progress.sql';
|
||||
$result = ['time' => date('c'), 'local_database' => true, 'column_previously_present' => $present,
|
||||
'migration_sha256' => hash_file('sha256', $sqlFile), 'applied' => false];
|
||||
if (in_array('--apply', $argv, true)) {
|
||||
Db::execute('SET SESSION lock_wait_timeout = 5');
|
||||
foreach (explode(';', preg_replace('/^--.*$/m', '', file_get_contents($sqlFile))) as $statement) {
|
||||
if (trim($statement) !== '') { Db::execute($statement); }
|
||||
}
|
||||
$columns = Db::query("SHOW COLUMNS FROM `zyt_prescription_ai_task` LIKE 'progress_json'");
|
||||
if (count($columns) !== 1 || $columns[0]['Type'] !== 'varchar(2048)' || $columns[0]['Null'] !== 'YES') {
|
||||
throw new RuntimeException('Unexpected progress column definition');
|
||||
}
|
||||
$result['applied'] = true;
|
||||
$result['business_state_unchanged'] = $before === $snapshot();
|
||||
if (!$result['business_state_unchanged']) { throw new RuntimeException('Business task state changed during upgrade'); }
|
||||
}
|
||||
echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
|
||||
} catch (Throwable $e) {
|
||||
echo json_encode(['error' => get_class($e), 'code' => $e->getCode()]), PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"lane": "qwen",
|
||||
"old_pid": 36592,
|
||||
"new_pid": 7512,
|
||||
"started_at": "2026-09-10T09:56:47.4495394+08:00",
|
||||
"policy": "manual-prescription-available-evidence-v2",
|
||||
"historical_tasks_retried": false
|
||||
},
|
||||
{
|
||||
"lane": "openai",
|
||||
"old_pid": 4796,
|
||||
"new_pid": 9292,
|
||||
"started_at": "2026-09-10T09:56:47.8478717+08:00",
|
||||
"policy": "manual-prescription-available-evidence-v2",
|
||||
"historical_tasks_retried": false
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Read-only comparison diagnostic. Prints dosage units and structural fields only,
|
||||
// never herb names, report text, patient data, URLs or credentials.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
|
||||
use app\common\service\prescriptionai\PrescriptionAiCipher;
|
||||
use app\common\service\prescriptionai\PrescriptionAiPolicy;
|
||||
use think\facade\Db;
|
||||
|
||||
$batchId = (int) ($argv[1] ?? 5);
|
||||
$cipher = new PrescriptionAiCipher();
|
||||
$batch = Db::name('prescription_ai_batch')->where('id', $batchId)->find();
|
||||
$doctor = $cipher->decrypt((string) $batch['prescription_cipher'], 'prescription');
|
||||
$herbs = PrescriptionAiPolicy::decode($doctor['herbs'] ?? []);
|
||||
|
||||
$shape = static function (array $herb): array {
|
||||
return [
|
||||
'has_name' => trim((string) ($herb['name'] ?? '')) !== '',
|
||||
'dosage' => $herb['dosage'] ?? null,
|
||||
'unit' => $herb['unit'] ?? null,
|
||||
'dose_basis' => $herb['dose_basis'] ?? null,
|
||||
'processing' => $herb['processing'] ?? null,
|
||||
'formula_type' => $herb['formula_type'] ?? null,
|
||||
'keys' => array_keys($herb),
|
||||
];
|
||||
};
|
||||
|
||||
$out = ['batch_id' => $batchId, 'doctor' => [
|
||||
'dose_unit' => $doctor['dose_unit'] ?? null,
|
||||
'dose_basis' => $doctor['dose_basis'] ?? null,
|
||||
'prescription_type' => $doctor['prescription_type'] ?? null,
|
||||
'herb_count' => count($herbs),
|
||||
'herbs' => array_map($shape, array_slice($herbs, 0, 5)),
|
||||
]];
|
||||
|
||||
foreach (Db::name('prescription_ai_result')->where('batch_id', $batchId)->select()->toArray() as $row) {
|
||||
$body = $cipher->decrypt((string) $row['body_cipher'], 'result:' . $row['batch_id'] . ':' . $row['model_key']);
|
||||
$candidate = (array) ($body['candidate'] ?? []);
|
||||
$candidateHerbs = (array) ($candidate['herbs'] ?? []);
|
||||
$out['results'][] = [
|
||||
'result_id' => (int) $row['id'], 'model_key' => $row['model_key'],
|
||||
'candidate_status' => $candidate['status'] ?? null,
|
||||
'dose_basis' => $candidate['dose_basis'] ?? null,
|
||||
'prescription_type' => $candidate['prescription_type'] ?? null,
|
||||
'times_per_day' => $candidate['times_per_day'] ?? null,
|
||||
'usage_days' => $candidate['usage_days'] ?? null,
|
||||
'herb_count' => count($candidateHerbs),
|
||||
'herbs' => array_map($shape, array_slice($candidateHerbs, 0, 5)),
|
||||
'comparison_status' => $row['comparison_status'], 'comparison_reason_code' => $row['comparison_reason_code'],
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
try {
|
||||
$secret = (string) config('prescription_analysis.encryption_key', '');
|
||||
if ($secret === '') { $secret = trim((string) file_get_contents(root_path('runtime') . 'prescription_ai_private/snapshot.key')); }
|
||||
$cipher = new \app\common\service\prescriptionai\PrescriptionAiCipher($secret);
|
||||
$out = [];
|
||||
foreach (\think\facade\Db::name('prescription_ai_task')->where('batch_id', (int) \think\facade\Db::name('prescription_ai_subject')->where('prescription_id', 7556)->value('latest_batch_id'))->select()->toArray() as $task) {
|
||||
if (empty($task['progress_cipher'])) {
|
||||
$out[] = ['model' => $task['model_key'], 'status' => $task['status'], 'result_id' => $task['result_id']];
|
||||
continue;
|
||||
}
|
||||
$p = $cipher->decrypt($task['progress_cipher'], 'progress:' . $task['id']);
|
||||
$out[] = ['model' => $task['model_key'], 'status' => $task['status'], 'attempts' => $task['attempts'], 'manual_retries' => $task['manual_retries'],
|
||||
'error_code' => $task['error_code'], 'stage' => $p['stage'], 'calls' => $p['usage']['total_calls'],
|
||||
'next_run' => date('c', (int) $task['next_run_at']), 'updated' => date('c', (int) $task['updated_at']),
|
||||
'steps' => array_keys($p['steps']),
|
||||
'recent_calls' => array_map(static fn (array $call): array => array_intersect_key($call, array_flip(['stage', 'latency_ms', 'ok', 'file_count', 'error_code'])), array_slice($p['usage']['calls'], -4))];
|
||||
}
|
||||
echo json_encode(['time' => date('c'), 'tasks' => $out], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
|
||||
} catch (Throwable $e) { echo json_encode(['error' => get_class($e), 'code' => $e->getCode(), 'line' => $e->getLine(), 'file' => basename($e->getFile())]), PHP_EOL; exit(1); }
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
// Read-only API validation; clinical bodies remain in memory and are never printed.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
try {
|
||||
$batch = \think\facade\Db::name('prescription_ai_batch')->where('id', 1)->where('prescription_id', 7556)->find();
|
||||
$actor = (int) $batch['actor_id'];
|
||||
$info = \app\common\service\prescriptionai\PrescriptionAiAccess::actor($actor);
|
||||
$detail = \app\adminapi\logic\tcm\PrescriptionAiLogic::detail(1, $actor, $info);
|
||||
$models = [];
|
||||
foreach ($detail['models'] ?? [] as $key => $model) {
|
||||
$coverage = $model['coverage'] ?? [];
|
||||
$fileStatuses = [];
|
||||
$fileReasons = [];
|
||||
foreach ($coverage['files'] ?? [] as $file) {
|
||||
$status = (string) ($file['status'] ?? 'unknown');
|
||||
$fileStatuses[$status] = ($fileStatuses[$status] ?? 0) + 1;
|
||||
$reason = (string) ($file['reason'] ?? '');
|
||||
if ($reason !== '') { $fileReasons[$reason] = ($fileReasons[$reason] ?? 0) + 1; }
|
||||
}
|
||||
$models[$key] = ['status' => $model['status'] ?? null,
|
||||
'report_id' => $model['report_id'] ?? null, 'has_report' => !empty($model['report']),
|
||||
'candidate_status' => $model['candidate']['status'] ?? null,
|
||||
'coverage_complete' => $coverage['complete'] ?? null,
|
||||
'files' => $fileStatuses, 'file_reasons' => $fileReasons,
|
||||
'comparison_status' => $model['comparison']['status'] ?? null,
|
||||
'error_code' => $model['error_code'] ?? null];
|
||||
}
|
||||
$clinicalMissing = array_values(array_map(static fn (array $gap): string => (string) $gap['source_id'],
|
||||
array_filter($detail['missing'] ?? [], static fn (array $gap): bool => ($gap['code'] ?? '') === 'CRITICAL_CLINICAL_FACT_MISSING')));
|
||||
echo json_encode(['time' => date('c'), 'batch_id' => $detail['id'] ?? null, 'status' => $detail['status'] ?? null,
|
||||
'clinical_missing_fields' => $clinicalMissing, 'models' => $models], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
|
||||
} catch (Throwable $e) {
|
||||
echo json_encode(['error' => get_class($e), 'code' => $e->getCode()]), PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
require __DIR__ . '/check_queue.php';
|
||||
|
||||
use app\common\service\prescriptionai\PrescriptionAiCipher;
|
||||
use app\common\service\prescriptionai\PrescriptionAiGenerator;
|
||||
use think\facade\Db;
|
||||
|
||||
$secret = (string) config('prescription_analysis.encryption_key', '');
|
||||
if ($secret === '') {
|
||||
$secret = trim((string) file_get_contents(root_path('runtime') . 'prescription_ai_private/snapshot.key'));
|
||||
}
|
||||
$cipher = new PrescriptionAiCipher($secret);
|
||||
$batch = Db::name('prescription_ai_batch')->where('prescription_id', 7556)->order('id', 'desc')->find();
|
||||
$context = $cipher->decrypt((string) $batch['context_cipher'], 'context');
|
||||
$budget = max(6000, min(200000, (int) config('prescription_ai.manual_analysis.input_token_budget', 24000))) - 3500;
|
||||
$units = (new ReflectionMethod(PrescriptionAiGenerator::class, 'sourceUnits'))->invoke(null, $context['source']['records'], $budget);
|
||||
$chunks = (new ReflectionMethod(PrescriptionAiGenerator::class, 'pack'))->invoke(null, $units, $budget);
|
||||
$textPromptBytes = [];
|
||||
foreach ($chunks as $chunk) {
|
||||
$ids = array_values(array_unique(array_column($chunk, 'source_id')));
|
||||
$prompt = (new ReflectionMethod(PrescriptionAiGenerator::class, 'evidencePrompt'))->invoke(null, 'text', $ids,
|
||||
['patient' => $context['source']['patient'] ?? [], 'clinical_field_semantics' => $context['source']['clinical_field_semantics'] ?? [], 'records' => $chunk]);
|
||||
$textPromptBytes[] = strlen($prompt);
|
||||
}
|
||||
$attachmentStatuses = array_count_values(array_column($context['files'] ?? [], 'status'));
|
||||
$result = [];
|
||||
foreach (Db::name('prescription_ai_task')->where('batch_id', $batch['id'])->select()->toArray() as $task) {
|
||||
if (empty($task['progress_cipher'])) { continue; }
|
||||
$progress = $cipher->decrypt($task['progress_cipher'], 'progress:' . $task['id']);
|
||||
$item = ['model' => $task['model_key'], 'stage' => $progress['stage'], 'calls' => $progress['usage']['total_calls'], 'steps' => []];
|
||||
foreach ($progress['steps'] ?? [] as $key => $step) {
|
||||
$content = (string) ($step['value']['content'] ?? '');
|
||||
$decoded = json_decode(trim($content), true);
|
||||
$jsonError = json_last_error_msg();
|
||||
$fenced = preg_match('/\A```(?:json)?\s*(.*?)\s*```\z/s', trim($content), $match) === 1;
|
||||
$wrapped = $fenced ? json_decode($match[1], true) : null;
|
||||
$summary = ['step' => $key, 'bytes' => strlen($content), 'json_error' => $jsonError,
|
||||
'has_think_tag' => str_contains($content, '<think>'), 'whole_json_fence' => $fenced,
|
||||
'json_keys' => is_array($decoded) ? array_keys($decoded) : null,
|
||||
'fenced_json_keys' => is_array($wrapped) ? array_keys($wrapped) : null];
|
||||
if (str_starts_with($key, 'text:')) {
|
||||
$expected = array_values(array_unique(array_column($chunks[(int) substr($key, 5)], 'source_id')));
|
||||
$summary['expected_source_count'] = count($expected);
|
||||
$summary['raw_valid'] = (new ReflectionMethod(PrescriptionAiGenerator::class, 'parseEvidence'))->invoke(null, $content, $expected) !== null;
|
||||
$summary['fenced_valid'] = $fenced && (new ReflectionMethod(PrescriptionAiGenerator::class, 'parseEvidence'))->invoke(null, $match[1], $expected) !== null;
|
||||
$value = is_array($decoded) ? $decoded : (is_array($wrapped) ? $wrapped : []);
|
||||
$summary['field_types'] = array_map('get_debug_type', $value);
|
||||
if (is_array($value['covered_source_ids'] ?? null)) {
|
||||
$summary['covered_source_count'] = count($value['covered_source_ids']);
|
||||
$summary['missing_source_count'] = count(array_diff($expected, $value['covered_source_ids']));
|
||||
$summary['extra_source_count'] = count(array_diff($value['covered_source_ids'], $expected));
|
||||
}
|
||||
}
|
||||
if (str_starts_with($key, 'files:')) {
|
||||
$sendable = array_values(array_filter($context['files'], static fn (array $f): bool => $f['status'] !== 'restricted' && !empty($f['url'])));
|
||||
$fileBatch = array_chunk($sendable, 3)[(int) substr($key, 6)];
|
||||
$known = array_values(array_unique(array_merge(array_column($context['source']['records'], 'source_id'), array_column($context['files'], 'file_id'))));
|
||||
$value = (new ReflectionMethod(PrescriptionAiGenerator::class, 'object'))->invoke(null, $content);
|
||||
$summary['file_output_valid'] = (new ReflectionMethod(PrescriptionAiGenerator::class, 'parseFiles'))->invoke(null, $content, $fileBatch, $known) !== null;
|
||||
$summary['returned_count'] = is_array($value['files'] ?? null) ? count($value['files']) : null;
|
||||
$summary['expected_count'] = count($fileBatch);
|
||||
$summary['file_shapes'] = [];
|
||||
foreach ($value['files'] ?? [] as $file) {
|
||||
$refs = $file['evidence_references'] ?? null;
|
||||
$summary['file_shapes'][] = ['keys' => array_keys($file), 'types' => array_map('get_debug_type', $file),
|
||||
'status' => in_array($file['status'] ?? '', ['processed', 'unreadable', 'unsupported'], true) ? $file['status'] : 'INVALID',
|
||||
'expected_id' => in_array($file['file_id'] ?? null, array_column($fileBatch, 'file_id'), true),
|
||||
'findings_bytes' => is_string($file['findings'] ?? null) ? strlen($file['findings']) : null,
|
||||
'refs_count' => is_array($refs) ? count($refs) : null,
|
||||
'unknown_refs_count' => is_array($refs) && count(array_filter($refs, 'is_string')) === count($refs) ? count(array_diff($refs, $known)) : null];
|
||||
}
|
||||
}
|
||||
$item['steps'][] = $summary;
|
||||
}
|
||||
$result[] = $item;
|
||||
}
|
||||
echo json_encode(['text_chunks' => count($chunks), 'text_prompt_bytes' => $textPromptBytes, 'input_budget' => $budget + 3500,
|
||||
'attachments' => count($context['files'] ?? []), 'attachment_statuses' => $attachmentStatuses,
|
||||
'progress_shape_only' => $result], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
// Read-only: exercise actual permission-aware endpoints, print only public progress metadata.
|
||||
$root = dirname(__DIR__, 2) . '/server/';
|
||||
chdir($root);
|
||||
require $root . 'vendor/autoload.php';
|
||||
$app = new \think\App($root);
|
||||
$app->initialize();
|
||||
use think\facade\Db;
|
||||
use app\adminapi\logic\tcm\PrescriptionAiLogic as Api;
|
||||
use app\common\service\prescriptionai\PrescriptionAiAccess as Access;
|
||||
try {
|
||||
$batchId = (int) Db::name('prescription_ai_subject')->where('prescription_id', 7556)->value('latest_batch_id');
|
||||
$batch = Db::name('prescription_ai_batch')->where('id', $batchId)->find();
|
||||
$actor = (int) $batch['actor_id'];
|
||||
$info = Access::actor($actor);
|
||||
$started = microtime(true);
|
||||
$statuses = Api::statuses([7556], $actor, $info);
|
||||
$statusMs = round((microtime(true) - $started) * 1000, 1);
|
||||
$started = microtime(true);
|
||||
$detail = Api::detail($batchId, $actor, $info);
|
||||
$detailMs = round((microtime(true) - $started) * 1000, 1);
|
||||
$models = [];
|
||||
foreach ($detail['models'] ?? [] as $key => $model) {
|
||||
$models[$key] = ['status' => $model['status'], 'error_code' => $model['error_code'], 'progress' => $model['progress'] ?? null];
|
||||
}
|
||||
$out = ['time' => date('c'), 'batch_id' => $batchId, 'batch_status' => $detail['status'], 'models' => $models,
|
||||
'list_has_progress' => isset($statuses['items'][0]['progress']),
|
||||
'list_milliseconds' => $statusMs, 'detail_milliseconds' => $detailMs];
|
||||
echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
|
||||
} catch (Throwable $e) {
|
||||
echo json_encode(['error' => get_class($e), 'code' => $e->getCode()]), PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
// Read-only provider parameters. Does not submit patient data or generate a report.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
$cfg = (array) config('prescription_ai');
|
||||
$endpoint = (new ReflectionMethod(\app\common\service\DifyChatService::class, 'buildEndpoint'))->invoke(null, $cfg['base_url'], 'parameters');
|
||||
$out = [];
|
||||
foreach (['qwen', 'openai'] as $model) {
|
||||
$curl = curl_init($endpoint);
|
||||
curl_setopt_array($curl, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15, CURLOPT_CONNECTTIMEOUT => 5,
|
||||
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $cfg['models'][$model]['api_key']]]);
|
||||
$body = curl_exec($curl);
|
||||
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
$decoded = is_string($body) ? json_decode($body, true) : [];
|
||||
$files = (array) ($decoded['file_upload'] ?? []);
|
||||
$image = (array) ($files['image'] ?? []);
|
||||
$out[$model] = ['http_code' => $status, 'curl_errno' => curl_errno($curl),
|
||||
'files' => array_intersect_key($files, array_flip(['enabled', 'number_limits', 'allowed_file_types', 'allowed_file_extensions', 'allowed_file_upload_methods'])),
|
||||
'image' => array_intersect_key($image, array_flip(['enabled', 'number_limits', 'transfer_methods']))];
|
||||
curl_close($curl);
|
||||
}
|
||||
echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Read-only queue metadata diagnostic. Never print credentials or clinical content.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
|
||||
try {
|
||||
$out = [
|
||||
'php_now' => time(), 'php_local_time' => date('c'),
|
||||
'enabled' => (bool) config('prescription_analysis.enabled', false),
|
||||
'start_at' => (int) config('prescription_analysis.start_at', 0),
|
||||
'configured_key_present' => (string) config('prescription_analysis.encryption_key', '') !== '',
|
||||
'local_key_present' => is_file(root_path('runtime') . 'prescription_ai_private/snapshot.key'),
|
||||
'db_now' => \think\facade\Db::query('SELECT UNIX_TIMESTAMP() AS now')[0]['now'],
|
||||
];
|
||||
$fields = 'id,prescription_id,status,validity,trigger_type,wait_until,next_run_at,lock_until,prepare_attempts,error_code,cutoff_at,created_at,updated_at';
|
||||
$out['prescription_batches'] = \think\facade\Db::name('prescription_ai_batch')
|
||||
->where('prescription_id', 7556)->field($fields)->order('id', 'desc')->limit(5)->select()->toArray();
|
||||
$ids = array_column($out['prescription_batches'], 'id');
|
||||
$out['prescription_tasks'] = $ids ? \think\facade\Db::name('prescription_ai_task')->whereIn('batch_id', $ids)
|
||||
->field('id,batch_id,model_key,status,attempts,total_attempts,next_run_at,lock_until,error_code,result_id,started_at,finished_at,updated_at')
|
||||
->select()->toArray() : [];
|
||||
$out['batch_counts'] = \think\facade\Db::name('prescription_ai_batch')
|
||||
->field('status,COUNT(*) AS total,MIN(id) AS first_id,MAX(id) AS last_id')->group('status')->select()->toArray();
|
||||
$out['model_counts'] = \think\facade\Db::name('prescription_ai_task')
|
||||
->field('model_key,status,COUNT(*) AS total')->group('model_key,status')->select()->toArray();
|
||||
$out['active_preparation'] = \think\facade\Db::name('prescription_ai_batch')
|
||||
->where('lock_until', '>', time())->field($fields)->limit(10)->select()->toArray();
|
||||
echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
|
||||
} catch (\Throwable $error) {
|
||||
echo json_encode(['diagnostic_error' => get_class($error), 'code' => $error->getCode()]), PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
require __DIR__ . '/check_queue.php';
|
||||
$secret = (string) config('prescription_analysis.encryption_key', '');
|
||||
if ($secret === '') {
|
||||
$secret = trim((string) file_get_contents(root_path('runtime') . 'prescription_ai_private/snapshot.key'));
|
||||
}
|
||||
$cipher = new \app\common\service\prescriptionai\PrescriptionAiCipher($secret);
|
||||
$batch = \think\facade\Db::name('prescription_ai_batch')->where('id', 1)->where('prescription_id', 7556)->find();
|
||||
$context = $cipher->decrypt($batch['context_cipher'], 'context');
|
||||
$types = $hosts = $missing = [];
|
||||
$sendable = [];
|
||||
foreach ($context['files'] as $file) {
|
||||
$type = (string) ($file['type'] ?? 'unknown');
|
||||
$types[$type] = ($types[$type] ?? 0) + 1;
|
||||
$host = (string) (parse_url((string) ($file['url'] ?? ''), PHP_URL_HOST) ?: '(none)');
|
||||
$hosts[$host] = ($hosts[$host] ?? 0) + 1;
|
||||
if ($file['status'] !== 'restricted' && !empty($file['url'])) { $sendable[] = $file; }
|
||||
}
|
||||
$normalization = [];
|
||||
foreach (array_chunk($sendable, 3) as $files) {
|
||||
$wire = array_map(static fn (array $f): array => ['type' => $f['type'], 'url' => $f['url'], 'transfer_method' => 'remote_url'], $files);
|
||||
$value = (new ReflectionMethod(\app\common\service\DifyChatService::class, 'normalizeFiles'))->invoke(null, $wire, 3);
|
||||
$normalization[] = ['input' => count($wire), 'kept' => count($value['kept']), 'over_limit' => count($value['dropped'])];
|
||||
}
|
||||
foreach ($context['missing'] ?? [] as $item) {
|
||||
$code = (string) ($item['code'] ?? 'unknown');
|
||||
$missing[$code] = ($missing[$code] ?? 0) + 1;
|
||||
}
|
||||
echo json_encode(['source_shape_only' => [
|
||||
'attachment_types' => $types, 'attachment_hosts' => $hosts, 'missing_codes' => $missing,
|
||||
'attachment_batch_normalization' => $normalization,
|
||||
'max_files' => config('prescription_ai.max_files'), 'timeout' => config('prescription_ai.timeout'),
|
||||
]], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
try {
|
||||
$secret = (string) config('prescription_analysis.encryption_key', '');
|
||||
if ($secret === '') { $secret = trim((string) file_get_contents(root_path('runtime') . 'prescription_ai_private/snapshot.key')); }
|
||||
$cipher = new \app\common\service\prescriptionai\PrescriptionAiCipher($secret);
|
||||
$out = [];
|
||||
foreach (\think\facade\Db::name('prescription_ai_task')->where('batch_id', 1)->select()->toArray() as $task) {
|
||||
if (empty($task['progress_cipher'])) {
|
||||
$out[] = ['model' => $task['model_key'], 'status' => $task['status'], 'result_id' => $task['result_id']];
|
||||
continue;
|
||||
}
|
||||
$p = $cipher->decrypt($task['progress_cipher'], 'progress:' . $task['id']);
|
||||
$out[] = ['model' => $task['model_key'], 'status' => $task['status'], 'attempts' => $task['attempts'], 'manual_retries' => $task['manual_retries'],
|
||||
'error_code' => $task['error_code'], 'stage' => $p['stage'], 'calls' => $p['usage']['total_calls'],
|
||||
'next_run' => date('c', (int) $task['next_run_at']), 'updated' => date('c', (int) $task['updated_at']),
|
||||
'steps' => array_keys($p['steps']),
|
||||
'recent_calls' => array_map(static fn (array $call): array => array_intersect_key($call, array_flip(['stage', 'latency_ms', 'ok', 'file_count', 'error_code'])), array_slice($p['usage']['calls'], -4))];
|
||||
}
|
||||
echo json_encode(['time' => date('c'), 'tasks' => $out], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
|
||||
} catch (Throwable $e) { echo json_encode(['error' => get_class($e), 'code' => $e->getCode(), 'line' => $e->getLine(), 'file' => basename($e->getFile())]), PHP_EOL; exit(1); }
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Read-only diagnostic for preparation wait and model timing. Metadata and counts only;
|
||||
// never prints clinical content, attachment URLs, prompts or credentials.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
|
||||
use think\facade\Db;
|
||||
|
||||
$rxId = (int) ($argv[1] ?? 7556);
|
||||
$out = ['now' => time(), 'prescription_id' => $rxId];
|
||||
|
||||
$rx = Db::name('tcm_prescription')->where('id', $rxId)->field('id,diagnosis_id,appointment_id,patient_id,is_system_auto,update_time')->find();
|
||||
$out['prescription'] = $rx;
|
||||
$diagnosisId = (int) ($rx['diagnosis_id'] ?? 0);
|
||||
|
||||
$out['call_records'] = Db::name('tcm_call_record')->where('diagnosis_id', $diagnosisId)
|
||||
->field('id,diagnosis_id,status,transcription_status,transcription_session_id,transcription_segment_count,start_time,end_time,create_time,update_time,transcription_started_at,transcription_finished_at')
|
||||
->order('id', 'desc')->limit(10)->select()->toArray();
|
||||
foreach ($out['call_records'] as &$call) {
|
||||
$call['segment_total'] = (int) Db::name('tcm_call_transcript_segment')->where('call_record_id', $call['id'])->count();
|
||||
$call['segment_current_session'] = (string) $call['transcription_session_id'] !== ''
|
||||
? (int) Db::name('tcm_call_transcript_segment')->where('call_record_id', $call['id'])
|
||||
->where('transcription_session_id', $call['transcription_session_id'])->count()
|
||||
: 0;
|
||||
}
|
||||
unset($call);
|
||||
|
||||
$batches = Db::name('prescription_ai_batch')->where('prescription_id', $rxId)
|
||||
->field('id,status,validity,cutoff_at,decision_at,wait_until,next_run_at,created_at,updated_at,coverage_status,source_summary_json,missing_json,error_code')
|
||||
->order('id', 'desc')->limit(5)->select()->toArray();
|
||||
foreach ($batches as &$batch) {
|
||||
$batch['prepare_seconds'] = (int) $batch['cutoff_at'] > 0 ? (int) $batch['cutoff_at'] - (int) $batch['created_at'] : null;
|
||||
$batch['missing_codes'] = array_count_values(array_column(json_decode((string) $batch['missing_json'], true) ?: [], 'code'));
|
||||
unset($batch['missing_json']);
|
||||
}
|
||||
unset($batch);
|
||||
$out['batches'] = $batches;
|
||||
|
||||
$ids = array_column($batches, 'id');
|
||||
$out['tasks'] = $ids ? Db::name('prescription_ai_task')->whereIn('batch_id', $ids)
|
||||
->field('id,batch_id,model_key,status,attempts,total_attempts,error_code,started_at,finished_at,updated_at')
|
||||
->order('id')->select()->toArray() : [];
|
||||
foreach ($out['tasks'] as &$task) {
|
||||
$task['run_seconds'] = (int) $task['finished_at'] > 0 && (int) $task['started_at'] > 0
|
||||
? (int) $task['finished_at'] - (int) $task['started_at'] : null;
|
||||
}
|
||||
unset($task);
|
||||
|
||||
$taskIds = array_column($out['tasks'], 'id');
|
||||
$out['attempts'] = $taskIds ? Db::name('prescription_ai_attempt')->whereIn('task_id', $taskIds)
|
||||
->field('id,task_id,attempt_no,status,error_code,started_at,finished_at')->order('id')->limit(40)->select()->toArray() : [];
|
||||
|
||||
echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
|
||||
@@ -0,0 +1,35 @@
|
||||
[
|
||||
{
|
||||
"lane": "prepare",
|
||||
"old_pids": [
|
||||
25796
|
||||
],
|
||||
"new_pid": 16964,
|
||||
"started_at": "2026-09-10T11:55:23.8552926+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\prepare-fixes-20260910-115522.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\prepare-fixes-20260910-115522.stderr.log",
|
||||
"loaded": "transcript-wait-fix, request_timeout=240s, one format repair per stage"
|
||||
},
|
||||
{
|
||||
"lane": "qwen",
|
||||
"old_pids": [
|
||||
47796
|
||||
],
|
||||
"new_pid": 40500,
|
||||
"started_at": "2026-09-10T11:55:24.5947659+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-fixes-20260910-115522.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-fixes-20260910-115522.stderr.log",
|
||||
"loaded": "transcript-wait-fix, request_timeout=240s, one format repair per stage"
|
||||
},
|
||||
{
|
||||
"lane": "openai",
|
||||
"old_pids": [
|
||||
19152
|
||||
],
|
||||
"new_pid": 33772,
|
||||
"started_at": "2026-09-10T11:55:25.3312733+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-fixes-20260910-115522.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-fixes-20260910-115522.stderr.log",
|
||||
"loaded": "transcript-wait-fix, request_timeout=240s, one format repair per stage"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,35 @@
|
||||
[
|
||||
{
|
||||
"lane": "prepare",
|
||||
"old_pids": [
|
||||
16964
|
||||
],
|
||||
"new_pid": 19548,
|
||||
"started_at": "2026-09-10T12:24:55.5424202+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\prepare-fixes-20260910-122454.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\prepare-fixes-20260910-122454.stderr.log",
|
||||
"loaded": "transcript-wait-fix, request_timeout=240s, one format repair per stage"
|
||||
},
|
||||
{
|
||||
"lane": "qwen",
|
||||
"old_pids": [
|
||||
40500
|
||||
],
|
||||
"new_pid": 5836,
|
||||
"started_at": "2026-09-10T12:24:56.2231420+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-fixes-20260910-122454.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-fixes-20260910-122454.stderr.log",
|
||||
"loaded": "transcript-wait-fix, request_timeout=240s, one format repair per stage"
|
||||
},
|
||||
{
|
||||
"lane": "openai",
|
||||
"old_pids": [
|
||||
33772
|
||||
],
|
||||
"new_pid": 25176,
|
||||
"started_at": "2026-09-10T12:24:56.9236012+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-fixes-20260910-122454.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-fixes-20260910-122454.stderr.log",
|
||||
"loaded": "transcript-wait-fix, request_timeout=240s, one format repair per stage"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,35 @@
|
||||
[
|
||||
{
|
||||
"lane": "prepare",
|
||||
"old_pids": [
|
||||
19548
|
||||
],
|
||||
"new_pid": 22872,
|
||||
"started_at": "2026-09-10T13:22:16.1041976+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\prepare-fixes-20260910-132215.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\prepare-fixes-20260910-132215.stderr.log",
|
||||
"loaded": "transcript-wait-fix, request_timeout=240s, one format repair per stage"
|
||||
},
|
||||
{
|
||||
"lane": "qwen",
|
||||
"old_pids": [
|
||||
5836
|
||||
],
|
||||
"new_pid": 6872,
|
||||
"started_at": "2026-09-10T13:22:16.7639660+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-fixes-20260910-132215.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-fixes-20260910-132215.stderr.log",
|
||||
"loaded": "transcript-wait-fix, request_timeout=240s, one format repair per stage"
|
||||
},
|
||||
{
|
||||
"lane": "openai",
|
||||
"old_pids": [
|
||||
36332
|
||||
],
|
||||
"new_pid": 33836,
|
||||
"started_at": "2026-09-10T13:22:17.4568700+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-fixes-20260910-132215.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-fixes-20260910-132215.stderr.log",
|
||||
"loaded": "transcript-wait-fix, request_timeout=240s, one format repair per stage"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
$root = dirname(__DIR__, 2) . '/server/';
|
||||
chdir($root);
|
||||
require $root . 'vendor/autoload.php';
|
||||
$app = new \think\App($root);
|
||||
$app->initialize();
|
||||
try {
|
||||
$connection = (string) config('database.default');
|
||||
$cfg = (array) config('database.connections.' . $connection);
|
||||
$safe = [
|
||||
'local_database' => in_array((string) ($cfg['hostname'] ?? ''), ['127.0.0.1', 'localhost', '::1'], true),
|
||||
'table_prefix_valid' => preg_match('/^[a-zA-Z0-9_]*$/D', (string) ($cfg['prefix'] ?? '')) === 1,
|
||||
'progress_column_present' => isset(\think\facade\Db::name('prescription_ai_task')->getFields()['progress_json']),
|
||||
'running_models' => \think\facade\Db::name('prescription_ai_task')->where('status', 'running')->field('model_key,COUNT(*) AS count')->group('model_key')->select()->toArray(),
|
||||
'active_preparation_count' => \think\facade\Db::name('prescription_ai_batch')->where('lock_until', '>', time())->count(),
|
||||
'active_batch_count' => \think\facade\Db::name('prescription_ai_batch')->where('validity', 'current')->whereIn('status', ['preparing', 'waiting_sources', 'queued', 'running', 'retry_wait'])->count(),
|
||||
'active_task_count' => \think\facade\Db::name('prescription_ai_task')->whereIn('status', ['queued', 'running', 'retry_wait'])->count(),
|
||||
];
|
||||
echo json_encode($safe, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;
|
||||
} catch (\Throwable $e) {
|
||||
echo json_encode(['error' => get_class($e)]), PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Row-level comparison diagnostic: prints normalized identity keys and match types so a
|
||||
// scoring mismatch can be traced. Herb identities only; no patient data or report text.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
|
||||
use app\common\model\doctor\Medicine;
|
||||
use app\common\service\prescriptionai\PrescriptionAiCipher;
|
||||
use app\common\service\prescriptionai\PrescriptionAiComparison;
|
||||
use app\common\service\prescriptionai\PrescriptionAiPolicy;
|
||||
use think\facade\Db;
|
||||
|
||||
$batchId = (int) ($argv[1] ?? 6);
|
||||
$model = (string) ($argv[2] ?? 'qwen');
|
||||
$cipher = new PrescriptionAiCipher();
|
||||
$batch = Db::name('prescription_ai_batch')->where('id', $batchId)->find();
|
||||
$doctor = $cipher->decrypt((string) $batch['prescription_cipher'], 'prescription');
|
||||
$doctor['herbs'] = PrescriptionAiPolicy::decode($doctor['herbs'] ?? []);
|
||||
$doctor['aux_usage'] = PrescriptionAiPolicy::decode($doctor['aux_usage'] ?? []);
|
||||
$row = Db::name('prescription_ai_result')->where('batch_id', $batchId)->where('model_key', $model)->find();
|
||||
$body = $cipher->decrypt((string) $row['body_cipher'], 'result:' . $row['batch_id'] . ':' . $row['model_key']);
|
||||
$catalog = Medicine::where('status', 1)->whereNull('delete_time')->field(['id', 'name', 'unit'])->order('id')->select()->toArray();
|
||||
$comparison = PrescriptionAiComparison::compare($doctor, (array) ($body['candidate'] ?? []), $catalog);
|
||||
|
||||
$rows = array_map(static fn (array $r): array => [
|
||||
'key' => $r['key'], 'name' => $r['name'], 'role' => $r['formula_type'], 'match' => $r['match_type'],
|
||||
'doctor' => $r['doctor_dosage'], 'candidate' => $r['candidate_dosage'], 'contribution' => $r['contribution'],
|
||||
], $comparison['rows']);
|
||||
echo json_encode([
|
||||
'batch' => $batchId, 'model' => $model, 'score' => $comparison['score'], 'herb_score' => $comparison['herb_score'],
|
||||
'doctor_count' => $comparison['doctor_count'], 'candidate_count' => $comparison['candidate_count'],
|
||||
'matched' => $comparison['matched_count'],
|
||||
'doctor_defaults' => count($comparison['normalization']['doctor']['defaults']),
|
||||
'doctor_merges' => $comparison['normalization']['doctor']['merges'],
|
||||
'rows' => $rows,
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
|
||||
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"lane": "qwen",
|
||||
"old_pid": 22252,
|
||||
"new_pid": 37984,
|
||||
"started_at": "2026-09-10T09:33:31.3573771+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-20260910-093330.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-20260910-093330.stderr.log"
|
||||
},
|
||||
{
|
||||
"lane": "openai",
|
||||
"old_pid": 22300,
|
||||
"new_pid": 43480,
|
||||
"started_at": "2026-09-10T09:33:31.7827284+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-20260910-093330.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-20260910-093330.stderr.log"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"lane": "qwen",
|
||||
"old_pid": 37984,
|
||||
"new_pid": 36592,
|
||||
"started_at": "2026-09-10T09:39:54.9335396+08:00",
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-20260910-093954.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-20260910-093954.stderr.log"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,2 @@
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,558 @@
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
PRESCRIPTION_AI storage_or_configuration_error think\db\exception\PDOException@PDOConnection.php:836
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"lane": "openai",
|
||||
"old_pid": 43480,
|
||||
"new_pid": 4796,
|
||||
"started_at": "2026-09-10T09:42:12.6466672+08:00",
|
||||
"reason": "Load validated cache and attachment batching fixes; no task retried"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,830 @@
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
PRESCRIPTION_AI storage_or_configuration_error
|
||||
@@ -0,0 +1,3 @@
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,3 @@
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,3 @@
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,2 @@
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,3 @@
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"openai","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"time": "2026-09-10T09:42:39+08:00",
|
||||
"batch_id": 1,
|
||||
"status": "partial",
|
||||
"models": {
|
||||
"openai": {
|
||||
"status": "success",
|
||||
"report_id": 1,
|
||||
"has_report": true,
|
||||
"candidate_status": "insufficient_data",
|
||||
"coverage_complete": false,
|
||||
"files": {
|
||||
"restricted": 2,
|
||||
"unsupported": 20
|
||||
},
|
||||
"file_reasons": {
|
||||
"FILE_UNAVAILABLE_OR_UNSUPPORTED": 2,
|
||||
"UPSTREAM_REJECTED": 20
|
||||
},
|
||||
"comparison_status": "not_comparable",
|
||||
"error_code": ""
|
||||
},
|
||||
"qwen": {
|
||||
"status": "failed",
|
||||
"report_id": 0,
|
||||
"has_report": false,
|
||||
"candidate_status": null,
|
||||
"coverage_complete": null,
|
||||
"files": [],
|
||||
"file_reasons": [],
|
||||
"comparison_status": null,
|
||||
"error_code": "INVALID_FILE_EVIDENCE_OUTPUT"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
[
|
||||
{
|
||||
"lane": "prepare",
|
||||
"instance": 1,
|
||||
"pid": 23076,
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\prepare-1-parallel-20260910-144827.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\prepare-1-parallel-20260910-144827.stderr.log"
|
||||
},
|
||||
{
|
||||
"lane": "qwen",
|
||||
"instance": 1,
|
||||
"pid": 19592,
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-1-parallel-20260910-144827.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-1-parallel-20260910-144827.stderr.log"
|
||||
},
|
||||
{
|
||||
"lane": "qwen",
|
||||
"instance": 2,
|
||||
"pid": 24824,
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-2-parallel-20260910-144827.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\qwen-2-parallel-20260910-144827.stderr.log"
|
||||
},
|
||||
{
|
||||
"lane": "openai",
|
||||
"instance": 1,
|
||||
"pid": 19924,
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-1-parallel-20260910-144827.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-1-parallel-20260910-144827.stderr.log"
|
||||
},
|
||||
{
|
||||
"lane": "openai",
|
||||
"instance": 2,
|
||||
"pid": 31592,
|
||||
"stdout": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-2-parallel-20260910-144827.stdout.log",
|
||||
"stderr": "D:\\web\\zyt\\artifacts\\prescription-ai-runtime\\openai-2-parallel-20260910-144827.stderr.log"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,3 @@
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,63 @@
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,4 @@
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
PRESCRIPTION_AI {"lane":"prepare","enabled":true,"processed":true}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Synthetic end-to-end probe of the candidate stage against the real model app.
|
||||
// Uses invented demo evidence only - no patient record, no attachment, no clinical database read.
|
||||
// Prints validation outcomes and rule names, never the model's answer.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
|
||||
use app\common\service\prescriptionai\PrescriptionAiGenerator;
|
||||
|
||||
$model = (string) ($argv[1] ?? 'qwen');
|
||||
$context = [
|
||||
'source_hash' => hash('sha256', 'synthetic-probe-' . $model),
|
||||
'missing' => [],
|
||||
'files' => [],
|
||||
'source' => [
|
||||
'dispensing' => ['formulation' => '浓缩水丸', 'unit' => 'g', 'dose_basis' => 'per_dose'],
|
||||
'patient' => ['age' => 52, 'gender' => 1],
|
||||
'records' => [[
|
||||
'source_id' => 'diagnoses:1', 'kind' => 'diagnoses',
|
||||
'data' => [
|
||||
'chief_complaint' => '示例:乏力、口干三个月,无发热',
|
||||
'allergy_history' => '示例:明确否认药物过敏',
|
||||
'current_medications' => '示例:未使用中西药',
|
||||
'tongue' => '示例:舌淡红苔薄白',
|
||||
],
|
||||
]],
|
||||
],
|
||||
'_comparison_catalog' => [
|
||||
['id' => 1, 'name' => '生黄芪'], ['id' => 2, 'name' => '党参'], ['id' => 3, 'name' => '麸炒白术'],
|
||||
['id' => 4, 'name' => '茯苓'], ['id' => 5, 'name' => '生麦冬'], ['id' => 6, 'name' => '五味子'],
|
||||
],
|
||||
];
|
||||
|
||||
$progress = [];
|
||||
$started = microtime(true);
|
||||
$result = PrescriptionAiGenerator::generate($model, $context, static function (array $state) use (&$progress): bool {
|
||||
$progress = $state;
|
||||
return true;
|
||||
});
|
||||
|
||||
echo json_encode([
|
||||
'model' => $model,
|
||||
'ok' => (bool) ($result['ok'] ?? false),
|
||||
'error_code' => $result['error_code'] ?? '',
|
||||
'retryable' => $result['retryable'] ?? null,
|
||||
'candidate_status' => $result['candidate']['status'] ?? null,
|
||||
'candidate_herb_count' => is_array($result['candidate']['herbs'] ?? null) ? count($result['candidate']['herbs']) : null,
|
||||
'prompt_version' => $result['prompt_version'] ?? '',
|
||||
'wall_seconds' => round(microtime(true) - $started, 1),
|
||||
'total_calls' => $progress['usage']['total_calls'] ?? null,
|
||||
'format_rejects' => $progress['format_rejects'] ?? [],
|
||||
'calls' => array_map(static fn (array $call): array => [
|
||||
'stage' => $call['stage'], 'ok' => $call['ok'], 'latency_ms' => $call['latency_ms'],
|
||||
'input_bytes' => $call['input_token_upper_bound'], 'error_code' => $call['error_code'],
|
||||
'completion_tokens' => $call['usage']['completion_tokens'] ?? null,
|
||||
], (array) ($progress['usage']['calls'] ?? [])),
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
// One bounded diagnostic request to the configured provider with an already-authorized attachment.
|
||||
// Never output the URL, key, request/response body or clinical findings.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
use app\common\service\DifyChatService as Chat;
|
||||
use app\common\service\prescriptionai\PrescriptionAiCipher as Cipher;
|
||||
try {
|
||||
$batch = \think\facade\Db::name('prescription_ai_batch')->where('id', 1)->where('prescription_id', 7556)->find();
|
||||
$secret = (string) config('prescription_analysis.encryption_key', '');
|
||||
if ($secret === '') { $secret = trim((string) file_get_contents(root_path('runtime') . 'prescription_ai_private/snapshot.key')); }
|
||||
$context = (new Cipher($secret))->decrypt($batch['context_cipher'], 'context');
|
||||
$files = array_values(array_filter($context['files'], static fn (array $f): bool => $f['status'] !== 'restricted' && !empty($f['url']) && $f['type'] === 'image'));
|
||||
$file = $files[0];
|
||||
$config = (array) config('prescription_ai');
|
||||
$model = $config['models']['openai'];
|
||||
$specs = (new ReflectionMethod(Chat::class, 'buildRequestSpecs'))->invoke(null, $config['base_url'], $model['name'], [],
|
||||
'附件传输检查。仅回复 OK,不输出或分析图片内容。', 'rxai-attachment-diagnostic', false,
|
||||
[['type' => 'image', 'transfer_method' => 'remote_url', 'url' => $file['url']]], []);
|
||||
$spec = $specs[0];
|
||||
$response = (new ReflectionMethod(Chat::class, 'sendRequest'))->invoke(null, $spec['url'], $spec['payload'], $model['api_key'], 10);
|
||||
$decoded = json_decode($response['body'], true);
|
||||
$message = strtolower((string) ($decoded['message'] ?? $decoded['error']['message'] ?? ''));
|
||||
$flags = [];
|
||||
foreach (['upload', 'disabled', 'image', 'vision', 'support', 'download', 'timeout', 'invalid', 'required', 'limit', 'file', 'extension', 'not allowed', 'format'] as $word) {
|
||||
if (str_contains($message, $word)) { $flags[] = $word; }
|
||||
}
|
||||
$technicalWords = explode(' ', 'file files is are the a an not no can cannot be must should remote local url transfer method uploaded upload unsupported supported allowed type types size large too exceeds maximum minimum empty missing exist exists found invalid valid param parameter parameters enabled enable disabled disable app application config configuration variable value values required mandatory in on of to and or for this image document content mime extension number count length user id does do set provided only accept accepts belong belongs owner permission access denied failed fetch download server request input inputs object list array string assistant prompt form unsupported_file_type');
|
||||
preg_match_all('/[a-z_]+/', $message, $words);
|
||||
$safeStructure = array_map(static fn (string $word): string => in_array($word, $technicalWords, true) ? $word : '[redacted]', $words[0]);
|
||||
$code = $decoded['code'] ?? $decoded['error']['code'] ?? '';
|
||||
echo json_encode(['protocol' => $spec['protocol'], 'http_code' => $response['http_code'], 'curl_errno' => $response['errno'],
|
||||
'provider_code' => is_string($code) && preg_match('/^[a-zA-Z0-9_]{1,80}$/', $code) ? $code : '', 'message_categories' => $flags,
|
||||
'technical_message_structure' => array_slice($safeStructure, 0, 35)]), PHP_EOL;
|
||||
} catch (Throwable $e) {
|
||||
echo json_encode(['probe_error' => get_class($e), 'code' => $e->getCode()]), PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Synthetic upstream probe: measures the maximum JSON output a model app will return.
|
||||
// No patient data, no clinical content, no attachments. Prints sizes and token usage only.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
|
||||
use app\common\service\DifyChatService;
|
||||
|
||||
$model = (string) ($argv[1] ?? 'qwen');
|
||||
$count = (int) ($argv[2] ?? 200);
|
||||
$prompt = '这是一次接口容量测试,与任何患者无关。请只输出一个JSON对象,键为items,值为长度恰好为' . $count
|
||||
. '的数组,每个元素形如{"i":序号从1开始,"t":"第N条测试文本,用于测量输出长度,请写满约二十个汉字"}。不要输出解释文字。';
|
||||
$started = microtime(true);
|
||||
$response = DifyChatService::chat($model, [], $prompt, 'probe-output-limit-' . $model, [], [
|
||||
'strict_files' => true, 'timeout' => 240,
|
||||
]);
|
||||
$content = (string) ($response['content'] ?? '');
|
||||
$decoded = json_decode($content, true);
|
||||
echo json_encode([
|
||||
'model' => $model,
|
||||
'requested_items' => $count,
|
||||
'ok' => (bool) ($response['ok'] ?? false),
|
||||
'error_code' => $response['error_code'] ?? '',
|
||||
'latency_ms' => (int) ($response['latency_ms'] ?? 0),
|
||||
'wall_seconds' => round(microtime(true) - $started, 1),
|
||||
'content_bytes' => strlen($content),
|
||||
'usage' => $response['usage'] ?? null,
|
||||
'json_valid' => is_array($decoded),
|
||||
'json_error' => is_array($decoded) ? '' : json_last_error_msg(),
|
||||
'returned_items' => is_array($decoded) && is_array($decoded['items'] ?? null) ? count($decoded['items']) : null,
|
||||
'tail_sample' => mb_substr($content, -60),
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Read-only end-to-end rehearsal: runs one model branch on a frozen batch context with the
|
||||
// current code and compares the fresh candidate against the frozen doctor prescription.
|
||||
// Writes nothing. Prints identity mapping outcomes and scores; herb names only, no patient data.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
|
||||
use app\common\model\doctor\Medicine;
|
||||
use app\common\service\prescriptionai\PrescriptionAiCipher;
|
||||
use app\common\service\prescriptionai\PrescriptionAiComparison;
|
||||
use app\common\service\prescriptionai\PrescriptionAiGenerator;
|
||||
use app\common\service\prescriptionai\PrescriptionAiPolicy;
|
||||
use think\facade\Db;
|
||||
|
||||
$batchId = (int) ($argv[1] ?? 7);
|
||||
$model = (string) ($argv[2] ?? 'qwen');
|
||||
$cipher = new PrescriptionAiCipher();
|
||||
$batch = Db::name('prescription_ai_batch')->where('id', $batchId)->find();
|
||||
$context = $cipher->decrypt((string) $batch['context_cipher'], 'context');
|
||||
$catalog = Medicine::where('status', 1)->whereNull('delete_time')->field(['id', 'name', 'unit'])->order('id')->select()->toArray();
|
||||
$context['_comparison_catalog'] = $catalog;
|
||||
|
||||
$progress = [];
|
||||
$result = PrescriptionAiGenerator::generate($model, $context, static function (array $state) use (&$progress): bool {
|
||||
$progress = $state;
|
||||
return true;
|
||||
});
|
||||
$doctor = $cipher->decrypt((string) $batch['prescription_cipher'], 'prescription');
|
||||
$doctor['herbs'] = PrescriptionAiPolicy::decode($doctor['herbs'] ?? []);
|
||||
$doctor['aux_usage'] = PrescriptionAiPolicy::decode($doctor['aux_usage'] ?? []);
|
||||
$comparison = PrescriptionAiComparison::compare($doctor, (array) ($result['candidate'] ?? []), $catalog);
|
||||
|
||||
echo json_encode([
|
||||
'batch' => $batchId, 'model' => $model, 'ok' => (bool) ($result['ok'] ?? false),
|
||||
'error_code' => $result['error_code'] ?? '',
|
||||
'candidate_names' => array_map(static fn (array $h): string => (string) $h['name'], (array) ($result['candidate']['herbs'] ?? [])),
|
||||
'comparison' => [
|
||||
'status' => $comparison['status'], 'reason_code' => $comparison['reason_code'],
|
||||
'score' => $comparison['score'], 'herb_score' => $comparison['herb_score'],
|
||||
'doctor_count' => $comparison['doctor_count'], 'candidate_count' => $comparison['candidate_count'],
|
||||
'matched' => $comparison['matched_count'], 'issues' => count($comparison['normalization']['issues']),
|
||||
],
|
||||
'total_calls' => $progress['usage']['total_calls'] ?? null,
|
||||
'stages' => array_column((array) ($progress['usage']['calls'] ?? []), 'stage'),
|
||||
'format_rejects' => $progress['format_rejects'] ?? [],
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Read-only reproduction of one model branch against a frozen batch context, using the current
|
||||
// code. Writes nothing: no task claim, no result, no progress. Prints validation rule names,
|
||||
// stage timings and sizes only - never the model's answer or any clinical content.
|
||||
$serverRoot = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR;
|
||||
chdir($serverRoot);
|
||||
require $serverRoot . 'vendor/autoload.php';
|
||||
$app = new \think\App($serverRoot);
|
||||
$app->initialize();
|
||||
|
||||
use app\common\model\doctor\Medicine;
|
||||
use app\common\service\prescriptionai\PrescriptionAiCipher;
|
||||
use app\common\service\prescriptionai\PrescriptionAiGenerator;
|
||||
use think\facade\Db;
|
||||
|
||||
$batchId = (int) ($argv[1] ?? 7);
|
||||
$model = (string) ($argv[2] ?? 'qwen');
|
||||
$cipher = new PrescriptionAiCipher();
|
||||
$batch = Db::name('prescription_ai_batch')->where('id', $batchId)->find();
|
||||
if (!$batch || (string) $batch['context_cipher'] === '') {
|
||||
throw new RuntimeException('batch context is not prepared');
|
||||
}
|
||||
$context = $cipher->decrypt((string) $batch['context_cipher'], 'context');
|
||||
$context['_comparison_catalog'] = Medicine::where('status', 1)->whereNull('delete_time')
|
||||
->field(['id', 'name', 'unit'])->order('id')->select()->toArray();
|
||||
|
||||
$progress = [];
|
||||
$started = microtime(true);
|
||||
$result = PrescriptionAiGenerator::generate($model, $context, static function (array $state) use (&$progress): bool {
|
||||
$progress = $state;
|
||||
return true;
|
||||
});
|
||||
|
||||
echo json_encode([
|
||||
'batch' => $batchId,
|
||||
'model' => $model,
|
||||
'ok' => (bool) ($result['ok'] ?? false),
|
||||
'error_code' => $result['error_code'] ?? '',
|
||||
'candidate_status' => $result['candidate']['status'] ?? null,
|
||||
'candidate_herb_count' => is_array($result['candidate']['herbs'] ?? null) ? count($result['candidate']['herbs']) : null,
|
||||
'coverage_status' => $result['coverage']['status'] ?? null,
|
||||
'source_ids' => count((array) ($result['coverage']['source_ids'] ?? [])),
|
||||
'files' => count((array) ($result['coverage']['files'] ?? [])),
|
||||
'missing' => count((array) ($result['coverage']['missing'] ?? [])),
|
||||
'wall_seconds' => round(microtime(true) - $started, 1),
|
||||
'format_rejects' => $progress['format_rejects'] ?? [],
|
||||
'calls' => array_map(static fn (array $call): array => [
|
||||
'stage' => $call['stage'], 'ok' => $call['ok'], 'latency_ms' => $call['latency_ms'],
|
||||
'input_bytes' => $call['input_token_upper_bound'], 'files' => $call['file_count'],
|
||||
'error_code' => $call['error_code'], 'completion_tokens' => $call['usage']['completion_tokens'] ?? null,
|
||||
], (array) ($progress['usage']['calls'] ?? [])),
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"time": "2026-09-10T10:27:32+08:00",
|
||||
"batch_id": 2,
|
||||
"batch_status": "failed",
|
||||
"models": {
|
||||
"openai": {
|
||||
"status": "failed",
|
||||
"error_code": "UPSTREAM_TIMEOUT",
|
||||
"progress": {
|
||||
"stage": "failed",
|
||||
"stage_label": "处理失败",
|
||||
"phase": "failed",
|
||||
"completed_units": null,
|
||||
"total_units": null,
|
||||
"unit_label": "",
|
||||
"elapsed_seconds": 91,
|
||||
"stage_elapsed_seconds": 0,
|
||||
"wait_remaining_seconds": null,
|
||||
"updated_at": 1789006891,
|
||||
"server_time": 1789007252,
|
||||
"notice": "处理未完成,请查看失败原因。 耗时按本次尝试计算。",
|
||||
"attempt": 3
|
||||
}
|
||||
},
|
||||
"qwen": {
|
||||
"status": "failed",
|
||||
"error_code": "INVALID_REPORT_OUTPUT",
|
||||
"progress": {
|
||||
"stage": "failed",
|
||||
"stage_label": "处理失败",
|
||||
"phase": "failed",
|
||||
"completed_units": null,
|
||||
"total_units": null,
|
||||
"unit_label": "",
|
||||
"elapsed_seconds": 48,
|
||||
"stage_elapsed_seconds": 0,
|
||||
"wait_remaining_seconds": null,
|
||||
"updated_at": 1789006297,
|
||||
"server_time": 1789007252,
|
||||
"notice": "处理未完成,请查看失败原因。 耗时按本次尝试计算。",
|
||||
"attempt": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"list_has_progress": true,
|
||||
"list_milliseconds": 18.6,
|
||||
"detail_milliseconds": 5.3
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
# 处方 AI 真实进度后端审查记录
|
||||
|
||||
2026-09-10。范围仅为后端代码、SQL 迁移和隔离测试;未修改真实业务数据,未启动、停止或重启真实消费者,未调用模型接口。
|
||||
|
||||
## 实现
|
||||
|
||||
- 新增 `PrescriptionAiProgress`,只接收阶段、阶段状态、分组计数和时间戳;数据库 `progress_json` 是最多 2048 字符的小字段。标签、提示和单位全部由固定中文文案产生,绝不从模型内容、缓存步骤、URL、锁令牌或病例字段派生。
|
||||
- `models[key].progress` 在状态、历史和详情接口统一返回;`batch.progress` 返回资料准备、转写等待期限、自动继续说明等。模型结果正文无法覆盖可信的 `progress`。
|
||||
- 文字资料、附件、每轮证据汇总显示真实已处理组数。文字/汇总必须通过结构和引用校验才能递增;附件明确无法读取也计为已处理组,并说明不等于读懂全部附件。每轮汇总重新计数,不给出总百分比或预计结束时间。
|
||||
- 调用模型前持久化 `phase=waiting`;模型返回后显示本地处理;报告校验和处方对比有独立阶段。生成器内部原有 `stage=completed` 仅为内部兼容,公开阶段此时仍是 `validating`。公开完成必须由结果入库事务的 `success` 状态确认。
|
||||
- 正在运行的任务 90 秒无更新时只提示“暂无新的进度更新”,不据此断言模型超时或消费者失联。失败/待重试提示上次真实阶段。
|
||||
- 模型耗时明确为本次尝试耗时,重试重新开始阶段计时,等待重试不会增加上一次执行耗时。成功/失败通过 `finished_at` 冻结时间;批次历史使用已结束模型的时间,后续 `source_updated` 不增加原批次处理耗时。
|
||||
- 进度更新使用 `checkpoint(..., persistCache: false)`,不重新加密或覆盖不断增长的模型缓存。仅模型响应和已有的无效缓存清理继续保存完整密文;比较前也保留原缓存。相同秒内更新没有改变数据时仍会检查实际租约,避免错误拒绝合法任务。
|
||||
- 权限、资料版本、当前租约仍须通过原有检查。原调用计数、累计预算、重试策略、候选方案策略均保留,未增加模型调用。
|
||||
|
||||
## 数据库兼容与部署
|
||||
|
||||
新增迁移:`server/database/migrations/2026_09_10_prescription_ai_progress.sql`。
|
||||
|
||||
迁移依赖现有 `2026_09_09_prescription_ai_analysis.sql` 创建的任务表,只新增一个可空 `VARCHAR(2048)` 列,不修改原迁移或历史任务。新迁移重复执行已在独立 MySQL 验证;存在列时执行无结果集的 `SET` 空操作,普通 PDO 分语句执行也可重复运行。
|
||||
|
||||
在已连接并选中应用数据库的 MySQL 客户端执行:
|
||||
|
||||
```sql
|
||||
SOURCE D:/web/zyt/server/database/migrations/2026_09_10_prescription_ai_progress.sql;
|
||||
```
|
||||
|
||||
建议迁移后部署新代码。为兼容本地目录直接服务请求的滚动更新,Store 和 API 均缓存检查列是否存在:旧库不查询或写入不存在的列,仍使用原加密缓存继续/完成任务;公开界面返回诚实的“暂无分段进度记录”。进程缓存到退出为止,因此迁移后应在任务空闲时重新加载三个消费者。已在运行的旧代码任务不凭空补造分组进度,需等其自然完成。根任务负责真实迁移与空闲重启。
|
||||
|
||||
## 验证
|
||||
|
||||
所有 MySQL 测试只连接根任务建立的 `127.0.0.1:13379` 独立测试实例,每次建立随机 `prescription_ai_test_*` 数据库,正常结束删除自己的数据库。首次调试的重复迁移 `SELECT 1` 游标问题已修复,但其早期随机测试库可能残留在专用实例;由根任务随实例回收。
|
||||
|
||||
从 `D:\web\zyt` 执行的最终结果:
|
||||
|
||||
```powershell
|
||||
php server/tests/PrescriptionAiProgressTest.php
|
||||
# 38 checks passed
|
||||
php server/tests/PrescriptionAiGeneratorTest.php
|
||||
# passed,含原有预算、缓存清理、附件退化回归与新增真实进度断言
|
||||
php server/tests/PrescriptionAiComparisonTest.php
|
||||
# 252 checks passed
|
||||
php server/tests/PrescriptionAiPolicyTest.php
|
||||
# 20 checks passed
|
||||
$env:ZYT_AI_TEST_MYSQL_PORT='13379'
|
||||
php server/tests/PrescriptionAiQueueTest.php
|
||||
# 68 checks passed
|
||||
php server/tests/PrescriptionAiPipelineTest.php
|
||||
# 80 checks passed
|
||||
php server/tests/PrescriptionAiQueueTest.php --legacy-progress-schema
|
||||
# 66 checks passed
|
||||
php server/tests/PrescriptionAiPipelineTest.php --legacy-progress-schema
|
||||
# 75 checks passed
|
||||
```
|
||||
|
||||
八个新增/修改 PHP 文件的 `php -l` 均通过。SQL 监听断言确认状态、详情、历史查询模型任务时不读取 `progress_cipher` 或 `SELECT *`;元数据字段只包含标量。真实 Worker/Store/ORM 集成验证两个模型在入库前分别发布 `comparing`,保留原密文,且此时尚无对应结果。生成器验证四次正常调用只保存四次完整缓存,纯进度通知和校验计数不会额外保存完整缓存;恢复后不重复模型调用。拒绝 checkpoint、旧租约写入、无效证据和附件不可读取均有覆盖。
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"time": "2026-09-10T10:27:17+08:00",
|
||||
"local_database": true,
|
||||
"column_previously_present": false,
|
||||
"migration_sha256": "2f40743c06dc9622b51615413c32cf97e3e67239a8e7ed5434a61791c0b1c0f9",
|
||||
"applied": true,
|
||||
"business_state_unchanged": true
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
[auto]
|
||||
server-uuid=407e32b3-acbd-11f1-91cb-40c2ba93134c
|
||||
@@ -0,0 +1,794 @@
|
||||
657,3
|
||||
657,2
|
||||
657,1
|
||||
657,0
|
||||
656,3
|
||||
656,2
|
||||
656,1
|
||||
656,0
|
||||
655,4
|
||||
655,3
|
||||
655,2
|
||||
655,1
|
||||
655,0
|
||||
654,4
|
||||
654,3
|
||||
654,2
|
||||
654,1
|
||||
654,0
|
||||
653,4
|
||||
653,3
|
||||
653,2
|
||||
653,1
|
||||
653,0
|
||||
652,5
|
||||
652,4
|
||||
652,3
|
||||
652,2
|
||||
652,1
|
||||
652,0
|
||||
651,9
|
||||
651,8
|
||||
651,7
|
||||
651,6
|
||||
651,5
|
||||
651,4
|
||||
651,3
|
||||
651,2
|
||||
651,1
|
||||
651,0
|
||||
650,3
|
||||
650,2
|
||||
650,1
|
||||
650,0
|
||||
649,3
|
||||
649,2
|
||||
649,1
|
||||
649,0
|
||||
648,3
|
||||
648,2
|
||||
648,1
|
||||
648,0
|
||||
647,3
|
||||
647,2
|
||||
647,1
|
||||
647,0
|
||||
646,3
|
||||
646,2
|
||||
646,1
|
||||
646,0
|
||||
645,3
|
||||
645,2
|
||||
645,1
|
||||
645,0
|
||||
644,3
|
||||
644,2
|
||||
644,1
|
||||
644,0
|
||||
643,3
|
||||
643,2
|
||||
643,1
|
||||
643,0
|
||||
642,3
|
||||
642,2
|
||||
642,1
|
||||
642,0
|
||||
641,3
|
||||
641,2
|
||||
641,1
|
||||
641,0
|
||||
640,3
|
||||
640,2
|
||||
640,1
|
||||
640,0
|
||||
639,3
|
||||
639,2
|
||||
639,1
|
||||
639,0
|
||||
638,3
|
||||
638,2
|
||||
638,1
|
||||
638,0
|
||||
637,3
|
||||
637,2
|
||||
637,1
|
||||
637,0
|
||||
636,3
|
||||
636,2
|
||||
636,1
|
||||
636,0
|
||||
635,3
|
||||
635,2
|
||||
635,1
|
||||
635,0
|
||||
634,3
|
||||
634,2
|
||||
634,1
|
||||
634,0
|
||||
633,3
|
||||
633,2
|
||||
633,1
|
||||
633,0
|
||||
632,3
|
||||
632,2
|
||||
632,1
|
||||
632,0
|
||||
631,3
|
||||
631,2
|
||||
631,1
|
||||
631,0
|
||||
630,3
|
||||
630,2
|
||||
630,1
|
||||
630,0
|
||||
629,3
|
||||
629,2
|
||||
629,1
|
||||
629,0
|
||||
628,3
|
||||
628,2
|
||||
628,1
|
||||
628,0
|
||||
627,3
|
||||
627,2
|
||||
627,1
|
||||
627,0
|
||||
626,3
|
||||
626,2
|
||||
626,1
|
||||
626,0
|
||||
625,3
|
||||
625,2
|
||||
625,1
|
||||
625,0
|
||||
624,3
|
||||
624,2
|
||||
624,1
|
||||
624,0
|
||||
623,3
|
||||
623,2
|
||||
623,1
|
||||
623,0
|
||||
622,3
|
||||
622,2
|
||||
622,1
|
||||
622,0
|
||||
621,3
|
||||
621,2
|
||||
621,1
|
||||
621,0
|
||||
620,3
|
||||
620,2
|
||||
620,1
|
||||
620,0
|
||||
619,3
|
||||
619,2
|
||||
619,1
|
||||
619,0
|
||||
618,3
|
||||
618,2
|
||||
618,1
|
||||
618,0
|
||||
617,3
|
||||
617,2
|
||||
617,1
|
||||
617,0
|
||||
616,3
|
||||
616,2
|
||||
616,1
|
||||
616,0
|
||||
615,3
|
||||
615,2
|
||||
615,1
|
||||
615,0
|
||||
614,3
|
||||
614,2
|
||||
614,1
|
||||
614,0
|
||||
613,3
|
||||
613,2
|
||||
613,1
|
||||
613,0
|
||||
612,3
|
||||
612,2
|
||||
612,1
|
||||
612,0
|
||||
611,3
|
||||
611,2
|
||||
611,1
|
||||
611,0
|
||||
610,3
|
||||
610,2
|
||||
610,1
|
||||
610,0
|
||||
609,3
|
||||
609,2
|
||||
609,1
|
||||
609,0
|
||||
608,3
|
||||
608,2
|
||||
608,1
|
||||
608,0
|
||||
607,3
|
||||
607,2
|
||||
607,1
|
||||
607,0
|
||||
606,3
|
||||
606,2
|
||||
606,1
|
||||
606,0
|
||||
605,3
|
||||
605,2
|
||||
605,1
|
||||
605,0
|
||||
604,3
|
||||
604,2
|
||||
604,1
|
||||
604,0
|
||||
603,3
|
||||
603,2
|
||||
603,1
|
||||
603,0
|
||||
602,3
|
||||
602,2
|
||||
602,1
|
||||
602,0
|
||||
601,3
|
||||
601,2
|
||||
601,1
|
||||
601,0
|
||||
600,3
|
||||
600,2
|
||||
600,1
|
||||
600,0
|
||||
599,3
|
||||
599,2
|
||||
599,1
|
||||
599,0
|
||||
598,3
|
||||
598,2
|
||||
598,1
|
||||
598,0
|
||||
597,3
|
||||
597,2
|
||||
597,1
|
||||
597,0
|
||||
596,4
|
||||
596,3
|
||||
596,2
|
||||
596,1
|
||||
596,0
|
||||
595,3
|
||||
595,2
|
||||
595,1
|
||||
595,0
|
||||
594,5
|
||||
594,4
|
||||
594,3
|
||||
594,2
|
||||
594,1
|
||||
594,0
|
||||
593,3
|
||||
593,2
|
||||
593,1
|
||||
593,0
|
||||
592,3
|
||||
592,2
|
||||
592,1
|
||||
592,0
|
||||
14,9
|
||||
591,4
|
||||
591,3
|
||||
591,2
|
||||
591,1
|
||||
591,0
|
||||
590,4
|
||||
590,3
|
||||
590,2
|
||||
590,1
|
||||
590,0
|
||||
589,4
|
||||
589,3
|
||||
589,2
|
||||
589,1
|
||||
589,0
|
||||
588,5
|
||||
588,4
|
||||
588,3
|
||||
588,2
|
||||
588,1
|
||||
588,0
|
||||
587,9
|
||||
587,8
|
||||
587,7
|
||||
587,6
|
||||
587,5
|
||||
587,4
|
||||
587,3
|
||||
587,2
|
||||
587,1
|
||||
587,0
|
||||
586,3
|
||||
586,2
|
||||
586,1
|
||||
586,0
|
||||
585,3
|
||||
585,2
|
||||
585,1
|
||||
585,0
|
||||
584,3
|
||||
584,2
|
||||
584,1
|
||||
584,0
|
||||
583,3
|
||||
583,2
|
||||
583,1
|
||||
583,0
|
||||
582,3
|
||||
582,2
|
||||
582,1
|
||||
582,0
|
||||
581,3
|
||||
581,2
|
||||
581,1
|
||||
581,0
|
||||
580,3
|
||||
580,2
|
||||
580,1
|
||||
580,0
|
||||
579,3
|
||||
579,2
|
||||
579,1
|
||||
579,0
|
||||
578,3
|
||||
578,2
|
||||
578,1
|
||||
578,0
|
||||
577,3
|
||||
577,2
|
||||
577,1
|
||||
577,0
|
||||
576,3
|
||||
576,2
|
||||
576,1
|
||||
576,0
|
||||
575,3
|
||||
575,2
|
||||
575,1
|
||||
575,0
|
||||
574,3
|
||||
574,2
|
||||
574,1
|
||||
574,0
|
||||
573,3
|
||||
573,2
|
||||
573,1
|
||||
573,0
|
||||
572,3
|
||||
572,2
|
||||
572,1
|
||||
572,0
|
||||
571,3
|
||||
571,2
|
||||
571,1
|
||||
571,0
|
||||
570,3
|
||||
570,2
|
||||
570,1
|
||||
570,0
|
||||
569,3
|
||||
569,2
|
||||
569,1
|
||||
569,0
|
||||
568,3
|
||||
568,2
|
||||
568,1
|
||||
568,0
|
||||
567,3
|
||||
567,2
|
||||
567,1
|
||||
567,0
|
||||
566,3
|
||||
566,2
|
||||
566,1
|
||||
566,0
|
||||
565,3
|
||||
565,2
|
||||
565,1
|
||||
565,0
|
||||
564,3
|
||||
564,2
|
||||
564,1
|
||||
564,0
|
||||
563,3
|
||||
563,2
|
||||
563,1
|
||||
563,0
|
||||
562,3
|
||||
562,2
|
||||
562,1
|
||||
562,0
|
||||
561,3
|
||||
561,2
|
||||
561,1
|
||||
561,0
|
||||
560,3
|
||||
560,2
|
||||
560,1
|
||||
560,0
|
||||
559,3
|
||||
559,2
|
||||
559,1
|
||||
559,0
|
||||
558,3
|
||||
558,2
|
||||
558,1
|
||||
558,0
|
||||
557,3
|
||||
557,2
|
||||
557,1
|
||||
557,0
|
||||
556,3
|
||||
556,2
|
||||
556,1
|
||||
556,0
|
||||
555,3
|
||||
555,2
|
||||
555,1
|
||||
555,0
|
||||
554,3
|
||||
554,2
|
||||
554,1
|
||||
554,0
|
||||
553,3
|
||||
553,2
|
||||
553,1
|
||||
553,0
|
||||
552,3
|
||||
552,2
|
||||
552,1
|
||||
552,0
|
||||
551,3
|
||||
551,2
|
||||
551,1
|
||||
551,0
|
||||
550,3
|
||||
550,2
|
||||
550,1
|
||||
550,0
|
||||
549,3
|
||||
549,2
|
||||
549,1
|
||||
549,0
|
||||
548,3
|
||||
548,2
|
||||
548,1
|
||||
548,0
|
||||
547,3
|
||||
547,2
|
||||
547,1
|
||||
547,0
|
||||
546,4
|
||||
546,3
|
||||
546,2
|
||||
546,1
|
||||
546,0
|
||||
545,3
|
||||
545,2
|
||||
545,1
|
||||
545,0
|
||||
544,4
|
||||
544,3
|
||||
544,2
|
||||
544,1
|
||||
544,0
|
||||
543,4
|
||||
543,3
|
||||
543,2
|
||||
543,1
|
||||
543,0
|
||||
542,3
|
||||
542,2
|
||||
542,1
|
||||
542,0
|
||||
541,5
|
||||
541,4
|
||||
541,3
|
||||
541,2
|
||||
541,1
|
||||
541,0
|
||||
540,9
|
||||
540,8
|
||||
540,7
|
||||
540,6
|
||||
540,5
|
||||
540,4
|
||||
540,3
|
||||
540,2
|
||||
540,1
|
||||
540,0
|
||||
539,3
|
||||
539,2
|
||||
539,1
|
||||
539,0
|
||||
538,3
|
||||
538,2
|
||||
538,1
|
||||
538,0
|
||||
537,3
|
||||
537,2
|
||||
537,1
|
||||
537,0
|
||||
536,3
|
||||
536,2
|
||||
536,1
|
||||
536,0
|
||||
535,3
|
||||
535,2
|
||||
535,1
|
||||
535,0
|
||||
534,3
|
||||
534,2
|
||||
534,1
|
||||
534,0
|
||||
533,3
|
||||
533,2
|
||||
533,1
|
||||
533,0
|
||||
532,3
|
||||
532,2
|
||||
532,1
|
||||
532,0
|
||||
531,3
|
||||
531,2
|
||||
531,1
|
||||
531,0
|
||||
530,3
|
||||
530,2
|
||||
530,1
|
||||
530,0
|
||||
529,3
|
||||
529,2
|
||||
529,1
|
||||
529,0
|
||||
528,3
|
||||
528,2
|
||||
528,1
|
||||
528,0
|
||||
527,3
|
||||
527,2
|
||||
527,1
|
||||
527,0
|
||||
526,3
|
||||
526,2
|
||||
526,1
|
||||
526,0
|
||||
525,3
|
||||
525,2
|
||||
525,1
|
||||
525,0
|
||||
524,3
|
||||
524,2
|
||||
524,1
|
||||
524,0
|
||||
523,3
|
||||
523,2
|
||||
523,1
|
||||
523,0
|
||||
522,3
|
||||
522,2
|
||||
522,1
|
||||
522,0
|
||||
521,3
|
||||
521,2
|
||||
521,1
|
||||
521,0
|
||||
520,3
|
||||
520,2
|
||||
520,1
|
||||
520,0
|
||||
519,3
|
||||
519,2
|
||||
519,1
|
||||
519,0
|
||||
518,3
|
||||
518,2
|
||||
518,1
|
||||
518,0
|
||||
517,3
|
||||
517,2
|
||||
517,1
|
||||
517,0
|
||||
516,3
|
||||
516,2
|
||||
516,1
|
||||
516,0
|
||||
515,3
|
||||
515,2
|
||||
515,1
|
||||
515,0
|
||||
514,3
|
||||
514,2
|
||||
514,1
|
||||
514,0
|
||||
513,3
|
||||
513,2
|
||||
513,1
|
||||
513,0
|
||||
512,4
|
||||
512,3
|
||||
512,2
|
||||
512,1
|
||||
512,0
|
||||
511,3
|
||||
511,2
|
||||
511,1
|
||||
511,0
|
||||
510,3
|
||||
510,2
|
||||
510,1
|
||||
510,0
|
||||
509,3
|
||||
509,2
|
||||
509,1
|
||||
509,0
|
||||
508,3
|
||||
508,2
|
||||
508,1
|
||||
508,0
|
||||
507,3
|
||||
507,2
|
||||
507,1
|
||||
507,0
|
||||
506,3
|
||||
506,2
|
||||
506,1
|
||||
506,0
|
||||
505,3
|
||||
505,2
|
||||
505,1
|
||||
505,0
|
||||
504,3
|
||||
504,2
|
||||
504,1
|
||||
504,0
|
||||
503,3
|
||||
503,2
|
||||
503,1
|
||||
503,0
|
||||
502,3
|
||||
502,2
|
||||
502,1
|
||||
502,0
|
||||
501,3
|
||||
501,2
|
||||
501,1
|
||||
501,0
|
||||
500,3
|
||||
500,2
|
||||
500,1
|
||||
500,0
|
||||
499,3
|
||||
499,2
|
||||
499,1
|
||||
499,0
|
||||
498,3
|
||||
498,2
|
||||
498,1
|
||||
498,0
|
||||
497,3
|
||||
497,2
|
||||
497,1
|
||||
497,0
|
||||
496,3
|
||||
496,2
|
||||
496,1
|
||||
496,0
|
||||
495,3
|
||||
495,2
|
||||
495,1
|
||||
495,0
|
||||
494,3
|
||||
494,2
|
||||
494,1
|
||||
494,0
|
||||
493,3
|
||||
493,2
|
||||
493,1
|
||||
493,0
|
||||
492,3
|
||||
492,2
|
||||
492,1
|
||||
492,0
|
||||
491,3
|
||||
491,2
|
||||
491,1
|
||||
491,0
|
||||
490,3
|
||||
490,2
|
||||
490,1
|
||||
490,0
|
||||
489,3
|
||||
489,2
|
||||
489,1
|
||||
489,0
|
||||
488,3
|
||||
488,2
|
||||
488,1
|
||||
488,0
|
||||
487,3
|
||||
487,2
|
||||
487,1
|
||||
487,0
|
||||
486,3
|
||||
486,2
|
||||
486,1
|
||||
486,0
|
||||
485,3
|
||||
485,2
|
||||
485,1
|
||||
485,0
|
||||
484,3
|
||||
484,2
|
||||
484,1
|
||||
484,0
|
||||
483,3
|
||||
483,2
|
||||
483,1
|
||||
483,0
|
||||
482,3
|
||||
482,2
|
||||
482,1
|
||||
482,0
|
||||
481,3
|
||||
481,2
|
||||
481,1
|
||||
481,0
|
||||
480,3
|
||||
480,2
|
||||
480,1
|
||||
480,0
|
||||
479,3
|
||||
479,2
|
||||
479,1
|
||||
479,0
|
||||
478,3
|
||||
478,2
|
||||
478,1
|
||||
478,0
|
||||
477,3
|
||||
477,2
|
||||
477,1
|
||||
477,0
|
||||
476,3
|
||||
476,2
|
||||
476,1
|
||||
476,0
|
||||
475,3
|
||||
475,2
|
||||
475,1
|
||||
475,0
|
||||
474,3
|
||||
474,2
|
||||
474,1
|
||||
474,0
|
||||
473,3
|
||||
473,2
|
||||
473,1
|
||||
473,0
|
||||
472,3
|
||||
472,2
|
||||
472,1
|
||||
472,0
|
||||
471,3
|
||||
471,2
|
||||
471,1
|
||||
471,0
|
||||
470,3
|
||||
470,2
|
||||
470,1
|
||||
470,0
|
||||
469,4
|
||||
469,3
|
||||
469,2
|
||||
469,1
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user