feat(image): complete reviewed generation delivery
Memind CI / Test, build, and release guards (pull_request) Successful in 2m47s

This commit is contained in:
john
2026-07-20 20:04:44 +08:00
parent fc3d27aae0
commit 4b15610aa8
42 changed files with 1764 additions and 97 deletions
+46
View File
@@ -1007,6 +1007,14 @@ export function createLlmProviderService(
]);
}
function isDashScopeProviderRow(row) {
if (!row) return false;
const providerId = String(row.provider_id ?? '').trim();
const apiUrl = String(row.api_url ?? '').trim().toLowerCase();
if (providerId === 'custom_qwen') return true;
return apiUrl.includes('dashscope.aliyuncs.com');
}
// Lightweight in-memory flag so proxyFallback can skip DB query on text-only messages.
// Invalidated on every setVisionKey / clearVisionKey call.
let visionKeyConfiguredCache = null;
@@ -1964,9 +1972,47 @@ export function createLlmProviderService(
providerLabel: publicRow.providerLabel,
visionModel: publicRow.defaultModel,
availableModels: publicRow.models,
apiKeyMasked: publicRow.apiKeyMasked,
};
},
/** DashScope API Key shared by Qwen VL (审图) and Qwen-Image (生图). Prefers vision binding. */
async resolveDashScopeCredentials() {
const candidates = [];
const pushCandidate = (row, source, priority) => {
if (!row || !isDashScopeProviderRow(row)) return;
if (candidates.some((item) => item.row.id === row.id)) return;
candidates.push({ row, source, priority });
};
pushCandidate(await getVisionRow(), 'vision', 0);
pushCandidate(await getSelectedRow(), 'global', 1);
const [activeRows] = await pool.query(
'SELECT * FROM h5_llm_provider_keys WHERE status = ? ORDER BY is_vision_selected DESC, is_selected DESC, updated_at DESC',
['active'],
);
for (const row of activeRows ?? []) {
pushCandidate(row, 'pool', 2);
}
candidates.sort((left, right) => left.priority - right.priority);
for (const candidate of candidates) {
const apiKey = decryptRow(candidate.row);
if (!apiKey) continue;
const publicRow = rowToPublic(candidate.row, catalogItem(candidate.row.provider_id), apiKey);
return {
apiKey,
keyId: candidate.row.id,
keyName: candidate.row.name,
providerLabel: publicRow.providerLabel,
source: candidate.source,
apiKeyMasked: maskApiKey(apiKey),
};
}
return null;
},
async setVisionKey(keyId, model) {
const nextModel = String(model ?? '').trim();
if (!nextModel) return { ok: false, message: '请选择视觉模型' };