refactor(frontend): 策略生成默认大模型,仅保留「本次规则稿」选项

移除「使用大模型」与保存策略偏好;buildPayload 默认 generator=llm;勾选本次仅规则稿时走 rules。后端默认 use_llm_default 改为 true。

Made-with: Cursor
This commit is contained in:
hub-gif 2026-04-17 16:44:15 +08:00
parent 7d219feb3c
commit 1229e49dbe
4 changed files with 10 additions and 109 deletions

View File

@ -194,8 +194,8 @@ def get_default_report_config() -> dict[str, Any]:
def get_default_strategy_config() -> dict[str, Any]:
"""策略生成页独立默认(与 ``report_config`` 无关),供前端回填与 PATCH 合并。"""
return {
# 打开页面时是否默认勾选「使用大模型生成」
"use_llm_default": False,
# 默认走大模型润色;用户可在单次生成时勾选「仅规则稿」取消
"use_llm_default": True,
}

View File

@ -87,7 +87,7 @@ def validate_report_config_body(value: dict) -> dict:
_STRATEGY_CONFIG_ALLOWED_KEYS = frozenset({"use_llm_default"})
_DEFAULT_STRATEGY_CONFIG: dict[str, bool] = {"use_llm_default": False}
_DEFAULT_STRATEGY_CONFIG: dict[str, bool] = {"use_llm_default": True}
def validate_strategy_config_body(value: dict) -> dict:

View File

@ -9,7 +9,7 @@ from pipeline.serializers import validate_strategy_config_body
def test_validate_strategy_config_merges_default() -> None:
out = validate_strategy_config_body({})
assert out["use_llm_default"] is False
assert out["use_llm_default"] is True
def test_validate_strategy_config_unknown_key() -> None:

View File

@ -1,12 +1,7 @@
<script setup>
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { useRoute, useRouter, RouterLink } from 'vue-router'
import {
refreshJobs,
useJobs,
api,
strategyConfigDefaultsUrl,
} from '../../composables/useJobs'
import { refreshJobs, useJobs, api } from '../../composables/useJobs'
import {
generationInFlightKey,
withGenerationInFlight,
@ -38,12 +33,8 @@ const strategyGeneratingOtherTask = computed(
strategyDraftPendingJobId.value != null &&
strategyDraftPendingJobId.value !== selectedId.value,
)
const useLlm = ref(false)
/** 与报告页「仅规则稿」一致:勾选则本次只出规则策略稿,不调用大模型润色 */
/** 勾选则本次仅规则稿(不调用大模型);默认不勾选即走大模型 */
const rulesOnlyThisRun = ref(false)
const strategyDefaults = ref({ use_llm_default: false })
const strategySaveLoading = ref(false)
const strategySaveErr = ref('')
const decisions = reactive({
product_role: '',
@ -83,7 +74,7 @@ const stanceOptions = [
]
function buildPayload() {
const generator = rulesOnlyThisRun.value ? 'rules' : useLlm.value ? 'llm' : 'rules'
const generator = rulesOnlyThisRun.value ? 'rules' : 'llm'
return {
generator,
business_notes: businessNotes.value,
@ -112,59 +103,6 @@ function formatJobOption(j) {
return tail ? `#${j.id} · ${j.keyword} · ${tail}` : `#${j.id} · ${j.keyword}`
}
function applyStrategyConfigFromJob(job) {
const stored =
job && typeof job.strategy_config === 'object' && job.strategy_config !== null
? job.strategy_config
: {}
const eff = { ...strategyDefaults.value, ...stored }
useLlm.value = !!eff.use_llm_default
}
async function loadStrategyDefaults() {
try {
const r = await api(strategyConfigDefaultsUrl())
if (r.ok) {
strategyDefaults.value = await r.json()
}
} catch {
/* ignore */
}
}
async function saveStrategyPreferences() {
const id = selectedId.value
if (!id) return
strategySaveErr.value = ''
strategySaveLoading.value = true
try {
const r = await api(`/api/jobs/${id}/`, {
method: 'PATCH',
body: JSON.stringify({
strategy_config: { use_llm_default: useLlm.value },
}),
})
const text = await r.text()
if (!r.ok) {
try {
const j = JSON.parse(text)
strategySaveErr.value = j.detail || text
} catch {
strategySaveErr.value = text || `HTTP ${r.status}`
}
return
}
const updated = JSON.parse(text)
const idx = jobs.value.findIndex((x) => x.id === updated.id)
if (idx >= 0) jobs.value[idx] = updated
applyStrategyConfigFromJob(updated)
} catch (e) {
strategySaveErr.value = String(e)
} finally {
strategySaveLoading.value = false
}
}
async function loadList() {
try {
await refreshJobs()
@ -210,10 +148,7 @@ async function generateAndGoPreview() {
})
}
onMounted(async () => {
await loadStrategyDefaults()
await loadList()
})
onMounted(loadList)
watch(
() => route.query.job,
@ -232,23 +167,6 @@ watch(
},
{ immediate: true },
)
watch(selectedId, async () => {
strategySaveErr.value = ''
const id = selectedId.value
if (!id) return
try {
const r = await api(`/api/jobs/${id}/`)
if (r.ok) {
const j = await r.json()
const idx = jobs.value.findIndex((x) => x.id === j.id)
if (idx >= 0) jobs.value[idx] = j
applyStrategyConfigFromJob(j)
}
} catch {
/* ignore */
}
})
</script>
<template>
@ -256,20 +174,16 @@ watch(selectedId, async () => {
<section class="ma-card">
<h2>策略生成</h2>
<p class="hint-top">
选择<strong>已成功</strong>任务在下方填空与勾选策略页的默认选项保存在本任务的<strong>策略配置</strong>分析报告生成页的<strong>报告配置</strong>相互独立未勾选大模型时由规则生成策略底稿勾选后由大模型在底稿与同任务数据摘要基础上成稿需服务端已配置网关策略稿与宿主报告第九章的归纳<strong>默认对齐</strong>无需在此勾选提交后跳转到
选择<strong>已成功</strong>任务在下方填空与勾选<strong>默认</strong>使用大模型在规则底稿与同任务数据摘要基础上成稿需服务端已配置网关若需更快不调用智能服务可勾选本次仅生成规则稿策略配置分析报告生成页的<strong>报告配置</strong>相互独立策略稿与宿主报告第九章的归纳<strong>默认对齐</strong>提交后跳转到
<RouterLink to="/jd/strategy-view">策略稿预览</RouterLink>
未填项在文稿中仍保留占位提示
</p>
<div class="toolbar toolbar-col">
<div class="toolbar">
<label class="chk-inline">
<input v-model="rulesOnlyThisRun" type="checkbox" />
本次仅生成规则稿不做大模型全文润色更快不调用智能服务
</label>
<label class="chk-inline">
<input v-model="useLlm" type="checkbox" :disabled="rulesOnlyThisRun" />
使用大模型生成与上项互斥勾选上一项时本项无效
</label>
</div>
<div class="toolbar">
<label class="sel-label">任务</label>
@ -279,14 +193,6 @@ watch(selectedId, async () => {
{{ formatJobOption(j) }}
</option>
</select>
<button
type="button"
class="ma-btn ma-btn-secondary"
:disabled="!selectedId || strategySaveLoading"
@click="saveStrategyPreferences"
>
{{ strategySaveLoading ? '保存中…' : '保存策略偏好' }}
</button>
<button
type="button"
class="ma-btn ma-btn-primary"
@ -296,7 +202,6 @@ watch(selectedId, async () => {
{{ strategyGeneratingThisTask ? '生成中…' : '生成并前往预览' }}
</button>
</div>
<p v-if="strategySaveErr" class="ma-err">{{ strategySaveErr }}</p>
<p v-if="strategyGeneratingOtherTask" class="ma-warn-banner">
任务 #{{ strategyDraftPendingJobId }} 的策略稿正在生成中请稍候再切换任务或重复提交
</p>
@ -429,10 +334,6 @@ watch(selectedId, async () => {
gap: 0.75rem;
margin-bottom: 0.75rem;
}
.toolbar-col {
flex-direction: column;
align-items: stretch;
}
.sel-label {
font-size: 0.85rem;
font-weight: 500;