1+ <template >
2+ <div class =" space-y-4" >
3+ <!-- 过滤开关 -->
4+ <div class =" flex items-center gap-2" >
5+ <ToggleSwitch
6+ :modelValue =" modelValue?.enable"
7+ @update:modelValue =" handleEnableChange"
8+ inputId =" filter-enable-switch" />
9+ <label for =" filter-enable-switch" class =" text-sm text-gray-600 cursor-pointer" >
10+ 启用信息过滤
11+ </label >
12+ </div >
13+
14+ <!-- 过滤配置详情 -->
15+ <div v-if =" modelValue?.enable" class =" border rounded-lg p-4 space-y-4" >
16+ <!-- 过滤类型选择 -->
17+ <div >
18+ <label class =" block text-sm font-medium mb-2" >过滤类型</label >
19+ <div class =" flex gap-4" >
20+ <div class =" flex items-center gap-2" >
21+ <RadioButton
22+ :modelValue =" modelValue?.filterType"
23+ value =" js"
24+ inputId =" js-filter-type"
25+ @update:modelValue =" handleFilterTypeChange" />
26+ <label for =" js-filter-type" >JavaScript 过滤</label >
27+ </div >
28+ <div class =" flex items-center gap-2" >
29+ <RadioButton
30+ :modelValue =" modelValue?.filterType"
31+ value =" ai"
32+ inputId =" ai-filter-type"
33+ @update:modelValue =" handleFilterTypeChange" />
34+ <label for =" ai-filter-type" >AI 过滤</label >
35+ </div >
36+ </div >
37+ </div >
38+
39+ <!-- JavaScript 过滤配置 -->
40+ <div v-if =" modelValue?.filterType === 'js'" >
41+ <label class =" block text-sm font-medium mb-2" >JavaScript 过滤代码</label >
42+ <Textarea
43+ :modelValue =" modelValue?.jsFilter?.code"
44+ @update:modelValue =" handleJsCodeChange"
45+ placeholder =" // 编写过滤函数,接收数据项作为参数,返回 true 表示保留,false 表示过滤
46+ // 参数: item (单个数据项)
47+ // 返回: boolean (true: 保留, false: 过滤)
48+ function filterItem(item) {
49+ // 示例:只保留包含特定关键词的项
50+ return item.title && item.title.includes('重要');
51+ }"
52+ rows =" 6"
53+ class =" w-full font-mono text-sm" />
54+ <small class =" text-gray-500" >
55+ 编写一个过滤函数,函数接收一个数据项作为参数,返回 true 表示保留该项,false 表示过滤掉该项。
56+ 函数名为 filterItem,可以使用 JavaScript 的所有特性。
57+ </small >
58+ </div >
59+
60+ <!-- AI 过滤配置 -->
61+ <div v-if =" modelValue?.filterType === 'ai'" class =" space-y-4" >
62+ <div >
63+ <label class =" block text-sm font-medium mb-2" >AI 模型</label >
64+ <InputText
65+ :modelValue =" modelValue?.aiFilter?.model"
66+ @update:modelValue =" handleAiModelChange"
67+ placeholder =" 例如: qwen2.5:7b, llama3.2:3b"
68+ class =" w-full" />
69+ </div >
70+
71+ <div >
72+ <label class =" block text-sm font-medium mb-2" >过滤提示词</label >
73+ <Textarea
74+ :modelValue =" modelValue?.aiFilter?.prompt"
75+ @update:modelValue =" handleAiPromptChange"
76+ placeholder =" 请判断以下内容是否值得保留,请从重要性和相关性角度考虑..."
77+ rows =" 4"
78+ class =" w-full" />
79+ <small class =" text-gray-500" >
80+ 编写用于判断内容是否值得保留的提示词,AI 将根据此提示词对每个数据项进行判断。
81+ 让ai回答 "pass" 则会保留对应的数据项
82+ </small >
83+ </div >
84+
85+ <div >
86+ <label class =" block text-sm font-medium mb-2" >Ollama 服务地址</label >
87+ 对于本地的ollama服务,需要配置允许浏览器扩展访问的环境变量:https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-allow-additional-web-origins-to-access-ollama
88+ <InputText
89+ :modelValue =" modelValue?.aiFilter?.ollamaUrl"
90+ @update:modelValue =" handleAiUrlChange"
91+ placeholder =" 例如: http://localhost:11434"
92+ class =" w-full" />
93+ </div >
94+ </div >
95+ </div >
96+ </div >
97+ </template >
98+
99+ <script setup lang="ts">
100+ import type { FilterConfig } from ' @/entrypoints/background/service/dbService' ;
101+ import { InputText , RadioButton , Textarea , ToggleSwitch } from ' primevue'
102+
103+ interface Props {
104+ modelValue? : FilterConfig ;
105+ }
106+
107+ interface Emits {
108+ (e : ' update:modelValue' , value : FilterConfig ): void ;
109+ }
110+
111+ const props = withDefaults (defineProps <Props >(), {
112+ modelValue: undefined ,
113+ });
114+
115+ const emit = defineEmits <Emits >();
116+
117+ // 确保配置对象存在
118+ const ensureConfig = (): FilterConfig => {
119+ const current = props .modelValue ;
120+ if (! current ) {
121+ return {
122+ enable: false ,
123+ filterType: ' js' ,
124+ jsFilter: { code: ' ' },
125+ aiFilter: { model: ' ' , prompt: ' ' , ollamaUrl: ' ' },
126+ };
127+ }
128+
129+ // 确保所有必需的子属性都存在
130+ return {
131+ ... current ,
132+ filterType: current .filterType || ' js' ,
133+ jsFilter: current .jsFilter || { code: ' ' },
134+ aiFilter: current .aiFilter || { model: ' ' , prompt: ' ' , ollamaUrl: ' ' },
135+ };
136+ };
137+
138+ // 处理启用/禁用变化
139+ const handleEnableChange = (enabled : boolean ) => {
140+ const config = ensureConfig ();
141+ emit (' update:modelValue' , { ... config , enable: enabled });
142+ };
143+
144+ // 处理过滤类型变化
145+ const handleFilterTypeChange = (filterType : ' js' | ' ai' ) => {
146+ const config = ensureConfig ();
147+ emit (' update:modelValue' , { ... config , filterType });
148+ };
149+
150+ // 处理 JS 代码变化
151+ const handleJsCodeChange = (code : string | undefined ) => {
152+ const config = ensureConfig ();
153+ emit (' update:modelValue' , {
154+ ... config ,
155+ jsFilter: { ... config .jsFilter , code: code || ' ' },
156+ });
157+ };
158+
159+ // 处理 AI 模型变化
160+ const handleAiModelChange = (model : string | undefined ) => {
161+ const config = ensureConfig ();
162+ emit (' update:modelValue' , {
163+ ... config ,
164+ aiFilter: {
165+ model: model || ' ' ,
166+ prompt: config .aiFilter ?.prompt || ' ' ,
167+ ollamaUrl: config .aiFilter ?.ollamaUrl || ' '
168+ },
169+ });
170+ };
171+
172+ // 处理 AI 提示词变化
173+ const handleAiPromptChange = (prompt : string | undefined ) => {
174+ const config = ensureConfig ();
175+ emit (' update:modelValue' , {
176+ ... config ,
177+ aiFilter: {
178+ model: config .aiFilter ?.model || ' ' ,
179+ prompt: prompt || ' ' ,
180+ ollamaUrl: config .aiFilter ?.ollamaUrl || ' '
181+ },
182+ });
183+ };
184+
185+ // 处理 AI URL 变化
186+ const handleAiUrlChange = (url : string | undefined ) => {
187+ const config = ensureConfig ();
188+ emit (' update:modelValue' , {
189+ ... config ,
190+ aiFilter: {
191+ model: config .aiFilter ?.model || ' ' ,
192+ prompt: config .aiFilter ?.prompt || ' ' ,
193+ ollamaUrl: url || ' '
194+ },
195+ });
196+ };
197+ </script >
0 commit comments