| <!DOCTYPE html>
|
| <html lang="zh-CN">
|
| <head>
|
| <meta charset="UTF-8">
|
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| <title>药物-辅料相容性预测报告 | API Excipient Compatibility Assessment</title>
|
| <style>
|
| |
| |
|
|
| :root {
|
| --primary-color: #1a5f7a;
|
| --secondary-color: #2d8bb8;
|
| --accent-color: #57c5b6;
|
| --warning-color: #ffc107;
|
| --danger-color: #dc3545;
|
| --success-color: #28a745;
|
| --text-primary: #333333;
|
| --text-secondary: #666666;
|
| --bg-light: #f8f9fa;
|
| --border-color: #dee2e6;
|
| }
|
|
|
| * {
|
| margin: 0;
|
| padding: 0;
|
| box-sizing: border-box;
|
| }
|
|
|
| body {
|
| font-family: 'Segoe UI', 'Microsoft YaHei', Arial, sans-serif;
|
| line-height: 1.6;
|
| color: var(--text-primary);
|
| background: #ffffff;
|
| font-size: 14px;
|
| }
|
|
|
| |
| |
|
|
| .report-container {
|
| max-width: 1000px;
|
| margin: 0 auto;
|
| padding: 40px;
|
| background: #ffffff;
|
| }
|
|
|
| |
| |
|
|
| .report-header {
|
| border-bottom: 3px solid var(--primary-color);
|
| padding-bottom: 20px;
|
| margin-bottom: 30px;
|
| }
|
|
|
| .report-title {
|
| font-size: 24px;
|
| font-weight: bold;
|
| color: var(--primary-color);
|
| margin-bottom: 5px;
|
| }
|
|
|
| .report-subtitle {
|
| font-size: 14px;
|
| color: var(--text-secondary);
|
| text-transform: uppercase;
|
| letter-spacing: 1px;
|
| }
|
|
|
| .report-meta {
|
| float: right;
|
| text-align: right;
|
| font-size: 12px;
|
| color: var(--text-secondary);
|
| }
|
|
|
| .report-meta .meta-item {
|
| margin-bottom: 3px;
|
| }
|
|
|
| .report-meta .meta-label {
|
| font-weight: normal;
|
| }
|
|
|
| .report-meta .meta-value {
|
| font-weight: bold;
|
| color: var(--primary-color);
|
| }
|
|
|
| .clearfix::after {
|
| content: "";
|
| display: table;
|
| clear: both;
|
| }
|
|
|
| |
| |
|
|
| .section {
|
| margin-bottom: 30px;
|
| }
|
|
|
| .section-title {
|
| font-size: 16px;
|
| font-weight: bold;
|
| color: var(--primary-color);
|
| margin-bottom: 15px;
|
| padding-bottom: 8px;
|
| border-bottom: 2px solid var(--accent-color);
|
| }
|
|
|
| .section-title .en-title {
|
| font-weight: normal;
|
| color: var(--text-secondary);
|
| margin-left: 10px;
|
| }
|
|
|
| |
| |
|
|
| .two-column {
|
| display: grid;
|
| grid-template-columns: 1fr 1fr;
|
| gap: 30px;
|
| }
|
|
|
| .column {
|
| min-width: 0;
|
| }
|
|
|
| |
| |
|
|
| .structure-box {
|
| background: var(--bg-light);
|
| border: 1px solid var(--border-color);
|
| border-radius: 8px;
|
| padding: 20px;
|
| text-align: center;
|
| min-height: 200px;
|
| }
|
|
|
| .structure-image {
|
| max-width: 100%;
|
| max-height: 180px;
|
| margin-bottom: 10px;
|
| }
|
|
|
| .structure-caption {
|
| font-size: 11px;
|
| color: var(--text-secondary);
|
| font-style: italic;
|
| }
|
|
|
| .smiles-display {
|
| font-family: 'Courier New', monospace;
|
| font-size: 11px;
|
| word-break: break-all;
|
| color: var(--text-secondary);
|
| margin-top: 10px;
|
| padding: 8px;
|
| background: #ffffff;
|
| border-radius: 4px;
|
| }
|
|
|
| |
| |
|
|
| .properties-table {
|
| width: 100%;
|
| border-collapse: collapse;
|
| font-size: 13px;
|
| }
|
|
|
| .properties-table th,
|
| .properties-table td {
|
| padding: 10px 12px;
|
| text-align: left;
|
| border-bottom: 1px solid var(--border-color);
|
| }
|
|
|
| .properties-table th {
|
| background: var(--bg-light);
|
| font-weight: 600;
|
| color: var(--text-secondary);
|
| width: 40%;
|
| }
|
|
|
| .properties-table td {
|
| color: var(--text-primary);
|
| }
|
|
|
| |
| |
|
|
| .risk-chart {
|
| margin-top: 15px;
|
| padding: 15px;
|
| background: var(--bg-light);
|
| border-radius: 8px;
|
| }
|
|
|
| .risk-chart-title {
|
| font-size: 12px;
|
| font-weight: 600;
|
| color: var(--text-secondary);
|
| margin-bottom: 10px;
|
| }
|
|
|
| .risk-item {
|
| display: flex;
|
| align-items: center;
|
| margin-bottom: 8px;
|
| font-size: 12px;
|
| }
|
|
|
| .risk-label {
|
| width: 120px;
|
| color: var(--text-secondary);
|
| }
|
|
|
| .risk-bar {
|
| flex: 1;
|
| height: 8px;
|
| background: #e9ecef;
|
| border-radius: 4px;
|
| overflow: hidden;
|
| }
|
|
|
| .risk-fill {
|
| height: 100%;
|
| border-radius: 4px;
|
| transition: width 0.3s ease;
|
| }
|
|
|
| .risk-fill.low { background: var(--success-color); }
|
| .risk-fill.medium { background: var(--warning-color); }
|
| .risk-fill.high { background: var(--danger-color); }
|
|
|
| |
| |
|
|
| .reactive-groups {
|
| display: grid;
|
| grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
| gap: 15px;
|
| }
|
|
|
| .group-card {
|
| background: var(--bg-light);
|
| border: 1px solid var(--border-color);
|
| border-radius: 8px;
|
| padding: 15px;
|
| }
|
|
|
| .group-name {
|
| font-weight: 600;
|
| color: var(--primary-color);
|
| margin-bottom: 5px;
|
| }
|
|
|
| .group-property {
|
| font-size: 12px;
|
| color: var(--text-secondary);
|
| margin-bottom: 8px;
|
| }
|
|
|
| .group-reactions {
|
| font-size: 11px;
|
| }
|
|
|
| .reaction-tag {
|
| display: inline-block;
|
| background: var(--secondary-color);
|
| color: white;
|
| padding: 2px 8px;
|
| border-radius: 3px;
|
| margin: 2px;
|
| font-size: 10px;
|
| }
|
|
|
| |
| |
|
|
| .excipient-box {
|
| background: var(--bg-light);
|
| border: 1px solid var(--border-color);
|
| border-radius: 8px;
|
| padding: 20px;
|
| }
|
|
|
| .excipient-name {
|
| font-size: 16px;
|
| font-weight: 600;
|
| color: var(--primary-color);
|
| margin-bottom: 15px;
|
| }
|
|
|
| .impurity-alert {
|
| background: #fff3cd;
|
| border: 1px solid #ffc107;
|
| border-radius: 6px;
|
| padding: 12px 15px;
|
| margin-top: 15px;
|
| }
|
|
|
| .impurity-alert-title {
|
| font-weight: 600;
|
| color: #856404;
|
| margin-bottom: 8px;
|
| font-size: 13px;
|
| }
|
|
|
| .impurity-item {
|
| font-size: 12px;
|
| color: #856404;
|
| margin: 4px 0;
|
| }
|
|
|
| |
| |
|
|
| .mechanism-table {
|
| width: 100%;
|
| border-collapse: collapse;
|
| font-size: 12px;
|
| margin-top: 15px;
|
| }
|
|
|
| .mechanism-table th,
|
| .mechanism-table td {
|
| padding: 12px;
|
| text-align: left;
|
| border: 1px solid var(--border-color);
|
| vertical-align: top;
|
| }
|
|
|
| .mechanism-table th {
|
| background: var(--primary-color);
|
| color: white;
|
| font-weight: 600;
|
| }
|
|
|
| .mechanism-table tbody tr:nth-child(even) {
|
| background: var(--bg-light);
|
| }
|
|
|
| .risk-badge {
|
| display: inline-block;
|
| padding: 3px 10px;
|
| border-radius: 4px;
|
| font-size: 11px;
|
| font-weight: 600;
|
| }
|
|
|
| .risk-badge.none { background: #d4edda; color: #155724; }
|
| .risk-badge.low { background: #d1ecf1; color: #0c5460; }
|
| .risk-badge.medium { background: #fff3cd; color: #856404; }
|
| .risk-badge.high { background: #f8d7da; color: #721c24; }
|
|
|
| |
| |
|
|
| .strategy-box {
|
| background: #e8f4f8;
|
| border-left: 4px solid var(--primary-color);
|
| padding: 20px;
|
| margin-top: 15px;
|
| }
|
|
|
| .strategy-title {
|
| font-weight: 600;
|
| color: var(--primary-color);
|
| margin-bottom: 10px;
|
| }
|
|
|
| .strategy-list {
|
| list-style: none;
|
| }
|
|
|
| .strategy-list li {
|
| margin: 10px 0;
|
| padding-left: 25px;
|
| position: relative;
|
| }
|
|
|
| .strategy-list li::before {
|
| content: "●";
|
| position: absolute;
|
| left: 0;
|
| color: var(--accent-color);
|
| }
|
|
|
| .strategy-number {
|
| display: inline-block;
|
| width: 20px;
|
| height: 20px;
|
| background: var(--primary-color);
|
| color: white;
|
| border-radius: 50%;
|
| text-align: center;
|
| line-height: 20px;
|
| font-size: 11px;
|
| margin-right: 8px;
|
| }
|
|
|
| |
| |
|
|
| .report-footer {
|
| margin-top: 40px;
|
| padding-top: 20px;
|
| border-top: 1px solid var(--border-color);
|
| font-size: 11px;
|
| color: var(--text-secondary);
|
| }
|
|
|
| .disclaimer {
|
| background: #f8f9fa;
|
| padding: 15px;
|
| border-radius: 6px;
|
| margin-top: 15px;
|
| }
|
|
|
| .disclaimer-title {
|
| font-weight: 600;
|
| margin-bottom: 8px;
|
| }
|
|
|
| |
| |
|
|
| @media print {
|
| body {
|
| font-size: 12px;
|
| }
|
|
|
| .report-container {
|
| padding: 20px;
|
| }
|
|
|
| .section {
|
| page-break-inside: avoid;
|
| }
|
| }
|
| </style>
|
| </head>
|
| <body>
|
| <div class="report-container">
|
|
|
| <header class="report-header clearfix">
|
| <div class="report-meta">
|
| <div class="meta-item">
|
| <span class="meta-label">Report ID:</span>
|
| <span class="meta-value">{{ report_id }}</span>
|
| </div>
|
| <div class="meta-item">
|
| <span class="meta-label">Date:</span>
|
| <span class="meta-value">{{ date }}</span>
|
| </div>
|
| <div class="meta-item">
|
| <span class="meta-label">Target:</span>
|
| <span class="meta-value">{{ excipient_name_en }}</span>
|
| </div>
|
| </div>
|
| <h1 class="report-title">药物-辅料相容性预测报告</h1>
|
| <p class="report-subtitle">API Excipient Compatibility Assessment</p>
|
| </header>
|
|
|
|
|
| <div class="two-column">
|
| <div class="column">
|
| <section class="section">
|
| <h2 class="section-title">
|
| 1. API 结构与反应活性基团
|
| <span class="en-title">(Reactive Moieties)</span>
|
| </h2>
|
|
|
| <div class="structure-box">
|
| {% if structure_image %}
|
| <img src="{{ structure_image }}" alt="Molecular Structure" class="structure-image">
|
| <p class="structure-caption">Structure Rendered by MolRenderer</p>
|
| {% else %}
|
| <div style="padding: 40px 0; color: #999;">
|
| [结构图待生成]
|
| </div>
|
| {% endif %}
|
|
|
| {% if api_smiles %}
|
| <div class="smiles-display">
|
| SMILES: {{ api_smiles }}
|
| </div>
|
| {% endif %}
|
| </div>
|
|
|
| <div class="reactive-groups" style="margin-top: 20px;">
|
| {% for group in reactive_groups %}
|
| <div class="group-card">
|
| <div class="group-name">{{ group.name.cn }}</div>
|
| <div class="group-property">({{ group.name.en }})</div>
|
| <div class="group-property">性质: {{ group.property_type }}</div>
|
| <div class="group-reactions">
|
| {% for reaction in group.potential_reactions %}
|
| <span class="reaction-tag">{{ reaction.cn }}</span>
|
| {% endfor %}
|
| </div>
|
| </div>
|
| {% endfor %}
|
| </div>
|
| </section>
|
| </div>
|
|
|
| <div class="column">
|
| <section class="section">
|
| <h2 class="section-title">
|
| 2. 理化性质概览
|
| <span class="en-title">(Basic)</span>
|
| </h2>
|
|
|
| <table class="properties-table">
|
| <tr>
|
| <th>酸碱性:</th>
|
| <td>{{ physicochemical.acidity_basicity.cn if physicochemical else '-' }}</td>
|
| </tr>
|
| <tr>
|
| <th>LogP (Est):</th>
|
| <td>~{{ physicochemical.logp if physicochemical and physicochemical.logp else '-' }}</td>
|
| </tr>
|
| <tr>
|
| <th>H-Bond Donors:</th>
|
| <td>{{ physicochemical.h_bond_donors if physicochemical and physicochemical.h_bond_donors else '-' }} (~NH2)</td>
|
| </tr>
|
| <tr>
|
| <th>H-Bond Acceptors:</th>
|
| <td>{{ physicochemical.h_bond_acceptors if physicochemical and physicochemical.h_bond_acceptors else '-' }}</td>
|
| </tr>
|
| </table>
|
|
|
| <div class="risk-chart">
|
| <div class="risk-chart-title">风险评价 (Risk Profile)</div>
|
| <div class="risk-item">
|
| <span class="risk-label">Maillard Reaction</span>
|
| <div class="risk-bar">
|
| <div class="risk-fill {{ maillard_risk_class }}" style="width: {{ maillard_risk_width }}%;"></div>
|
| </div>
|
| </div>
|
| <div class="risk-item">
|
| <span class="risk-label">Hygroscopicity</span>
|
| <div class="risk-bar">
|
| <div class="risk-fill {{ hygro_risk_class }}" style="width: {{ hygro_risk_width }}%;"></div>
|
| </div>
|
| </div>
|
| <div class="risk-item">
|
| <span class="risk-label">Chemisorption</span>
|
| <div class="risk-bar">
|
| <div class="risk-fill {{ chem_risk_class }}" style="width: {{ chem_risk_width }}%;"></div>
|
| </div>
|
| </div>
|
| <div class="risk-item">
|
| <span class="risk-label">Oxidation</span>
|
| <div class="risk-bar">
|
| <div class="risk-fill {{ oxid_risk_class }}" style="width: {{ oxid_risk_width }}%;"></div>
|
| </div>
|
| </div>
|
| <div class="risk-item">
|
| <span class="risk-label">Hydrolysis</span>
|
| <div class="risk-bar">
|
| <div class="risk-fill {{ hydro_risk_class }}" style="width: {{ hydro_risk_width }}%;"></div>
|
| </div>
|
| </div>
|
| </div>
|
| </section>
|
| </div>
|
| </div>
|
|
|
|
|
| <section class="section">
|
| <h2 class="section-title">
|
| 3. 辅料属性:{{ excipient_name }}
|
| <span class="en-title">({{ excipient_name_en }})</span>
|
| </h2>
|
|
|
| <div class="two-column">
|
| <div class="column">
|
| <div class="excipient-box">
|
| <h3 style="color: var(--text-secondary); font-size: 13px; margin-bottom: 10px;">关键特性:</h3>
|
|
|
| {% if excipient_profile %}
|
| <ul style="font-size: 13px; padding-left: 20px;">
|
| {% if excipient_profile.formula %}
|
| <li>化学式: {{ excipient_profile.formula }}</li>
|
| {% endif %}
|
| {% for prop in excipient_profile.key_properties %}
|
| <li>{{ prop }}</li>
|
| {% endfor %}
|
| </ul>
|
| {% endif %}
|
| </div>
|
| </div>
|
|
|
| <div class="column">
|
| <div class="impurity-alert">
|
| <div class="impurity-alert-title">⚠ 关键杂质警示 (Impurity Profile)</div>
|
| <p style="font-size: 12px; color: #856404; margin-bottom: 10px;">
|
| 辅料的杂质谱是影响相容性的关键因素,需评估风险级别或查阅COA确认。
|
| </p>
|
| {% if excipient_profile and excipient_profile.impurity_profile %}
|
| <div class="impurity-item">Fe²⁺: ≤ {{ excipient_profile.impurity_profile.fe_ppm }} ppm Mn²⁺: ≤ {{ excipient_profile.impurity_profile.mn_ppm }} ppm</div>
|
| {% endif %}
|
| <div class="impurity-item">H₂O: ~0.5%</div>
|
| </div>
|
| </div>
|
| </div>
|
| </section>
|
|
|
|
|
| <section class="section">
|
| <h2 class="section-title">
|
| 4. 相容性机制预测
|
| <span class="en-title">(Mechanism of Interaction)</span>
|
| </h2>
|
|
|
| <table class="mechanism-table">
|
| <thead>
|
| <tr>
|
| <th style="width: 15%;">相互作用类型</th>
|
| <th style="width: 10%;">风险等级</th>
|
| <th style="width: 40%;">机制分析与专家点评</th>
|
| </tr>
|
| </thead>
|
| <tbody>
|
| {% for interaction in interactions %}
|
| <tr>
|
| <td>
|
| <strong>{{ interaction.reaction_type.cn }}</strong><br>
|
| <small style="color: #666;">({{ interaction.reaction_type.en }})</small>
|
| </td>
|
| <td>
|
| <span class="risk-badge {{ interaction.risk_level.value }}">
|
| {% if interaction.risk_level.value == 'none' %}无风险
|
| {% elif interaction.risk_level.value == 'low' %}低风险
|
| {% elif interaction.risk_level.value == 'medium' %}中等/关注
|
| {% else %}高风险{% endif %}
|
| </span>
|
| </td>
|
| <td>
|
| <p style="margin-bottom: 8px;">{{ interaction.mechanism_analysis }}</p>
|
| <p style="color: #666; font-size: 11px;"><em>点评: {{ interaction.expert_notes }}</em></p>
|
| </td>
|
| </tr>
|
| {% endfor %}
|
| </tbody>
|
| </table>
|
| </section>
|
|
|
|
|
| <section class="section">
|
| <div class="strategy-box">
|
| <h2 class="strategy-title">FORMULATION STRATEGY (处方策略建议)</h2>
|
|
|
| <ol style="padding-left: 20px; font-size: 13px;">
|
| {% for strategy in formulation_strategies %}
|
| <li style="margin: 12px 0;">
|
| <strong>{{ strategy.title }}</strong>: {{ strategy.description }}
|
| {% if strategy.rationale %}
|
| <br><small style="color: #666;">{{ strategy.rationale }}</small>
|
| {% endif %}
|
| </li>
|
| {% endfor %}
|
| </ol>
|
| </div>
|
| </section>
|
|
|
|
|
| <footer class="report-footer">
|
| <div class="disclaimer">
|
| <div class="disclaimer-title">报告说明 (Disclaimer)</div>
|
| <p>本报告基于SMILES结构推断与药学通用知识生成,文献和药典等第三方数据库收录的数据进行分析。实验验证(如Stress Testing)仍为相容性评估的最终标准。</p>
|
| <p style="margin-top: 8px;">
|
| <strong>假设:</strong> {{ assumptions | join('; ') }}
|
| </p>
|
| <p style="margin-top: 5px;">
|
| <strong>局限性:</strong> {{ limitations | join('; ') }}
|
| </p>
|
| </div>
|
| </footer>
|
| </div>
|
| </body>
|
| </html>
|
|
|