Files
kefu/deploy/knowledge-v3/edit_backend.py
T
2026-09-21 10:34:06 +08:00

100 lines
6.4 KiB
Python

from pathlib import Path
root = Path('C:/kefu/wechat_rpa')
def edit(name, old, new):
path = root / name
text = path.read_text(encoding='utf-8')
assert old in text, (name, old[:100])
path.write_text(text.replace(old, new), encoding='utf-8', newline='\n')
edit('knowledge_store.py', 'CREATE TABLE IF NOT EXISTS knowledge_settings (', '''CREATE TABLE IF NOT EXISTS knowledge_discarded (
tenant_id TEXT NOT NULL, dedup_hash TEXT NOT NULL, created_at TEXT NOT NULL,
PRIMARY KEY(tenant_id,dedup_hash)
);
CREATE TABLE IF NOT EXISTS knowledge_settings (''')
edit('knowledge_store.py', '("max_model_calls", 100, 10000)):', '("max_model_calls", 100, 10000), ("model_timeout_seconds", 90, 180)):')
edit('knowledge_store.py', ' options.update(date_start=start,', ''' if options['model_timeout_seconds'] < 30:
raise ValueError("模型等待时间应为 30 至 180 秒")
provider = options.get('model_provider_id', '')
if not isinstance(provider, str) or len(provider) > 128:
raise ValueError("模型标识无效")
options.update(date_start=start,''')
edit('knowledge_store.py', ' @staticmethod\n def _check_expiry(row):', ''' def delete_rejected(self, tenant, item_id, revision, actor, ip):
with self.database.connect() as db:
db.execute("BEGIN IMMEDIATE")
row = self._item(db, tenant, item_id)
if row['revision'] != revision or row['status'] != 'rejected':
raise ValueError('仅当前版本的已驳回知识可以删除,请刷新确认状态')
db.execute('INSERT OR IGNORE INTO knowledge_discarded VALUES (?,?,?)',
(tenant, row['dedup_hash'], utc_now()))
db.execute('DELETE FROM knowledge_fts WHERE item_id=?', (item_id,))
db.execute('DELETE FROM knowledge_source WHERE item_id=?', (item_id,))
db.execute('DELETE FROM knowledge_revision WHERE item_id=?', (item_id,))
db.execute('DELETE FROM knowledge_item WHERE id=? AND tenant_id=?', (item_id, tenant))
self.database._audit(db, actor, 'knowledge.delete', f'item={item_id} revision={revision}', ip)
return {'id': item_id, 'status': 'deleted'}
@staticmethod
def _check_expiry(row):''')
edit('knowledge_store.py', ' scope_key = fingerprint(json_text({k: options.get(k, "") for k in (', ''' if options['engine'] == 'model':
from knowledge_models import resolve_model
resolve_model(self.database, options)
scope_key = fingerprint(json_text({k: options.get(k, "") for k in (''')
edit('knowledge_store.py', '"date_end", "engine", "max_messages", "max_model_calls")', '"date_end", "engine", "max_messages", "max_model_calls", "model_provider_id", "model_timeout_seconds")')
edit('knowledge_store.py', ' def job_action(self, tenant, job_id, action, actor, ip):', ''' def configure_job(self, tenant, job_id, values, actor, ip):
options = dict(self.job(tenant, job_id)['options'])
options.update(values)
options = job_options(options)
if options['engine'] == 'model':
from knowledge_models import resolve_model
resolve_model(self.database, options)
with self.database.connect() as db:
db.execute('BEGIN IMMEDIATE')
row = db.execute('SELECT * FROM knowledge_job WHERE id=? AND tenant_id=?', (job_id, tenant)).fetchone()
if row is None:
raise KeyError('任务不存在')
if row['status'] not in {'paused', 'failed'}:
raise ValueError('请先暂停任务,再调整模型配置')
if options['engine'] == 'model' and options['max_model_calls'] <= row['model_calls']:
raise ValueError('模型调用总上限须大于已使用次数')
db.execute('UPDATE knowledge_job SET options_json=?,updated_at=? WHERE id=?',
(json_text(options), utc_now(), job_id))
self.database._audit(db, actor, 'knowledge.job.configure', f'job={job_id}', ip)
return self.job(tenant, job_id)
def job_action(self, tenant, job_id, action, actor, ip):''')
edit('knowledge_store.py', ' existing = db.execute("SELECT id,status FROM knowledge_item', ''' if db.execute('SELECT 1 FROM knowledge_discarded WHERE tenant_id=? AND dedup_hash=?', (tenant, digest)).fetchone():
return False
existing = db.execute("SELECT id,status FROM knowledge_item''')
edit('knowledge_api.py', ' max_messages: int = Field', ''' model_provider_id: str = Field(default="", max_length=128)
model_timeout_seconds: int = Field(default=90, ge=30, le=180)
max_messages: int = Field''')
edit('knowledge_api.py', 'class EditBody(BaseModel):', '''class JobConfigBody(BaseModel):
engine: Literal['rules', 'model']
model_provider_id: str = Field(default='', max_length=128)
model_timeout_seconds: int = Field(default=90, ge=30, le=180)
max_model_calls: int = Field(default=100, ge=1, le=10000)
class EditBody(BaseModel):''')
edit('knowledge_api.py', ' @app.get("/api/v2/knowledge/jobs")', ''' @app.get('/api/v2/knowledge/models')
def models(account_id: int | None = None, principal=Depends(require('knowledge:write', 'im:content:read'))):
single(principal, account_id)
from knowledge_models import model_choices
return {'items': model_choices(database)}
@app.put('/api/v2/knowledge/jobs/{job_id}/config')
def job_config(job_id: str, body: JobConfigBody, request: Request, account_id: int | None = None,
principal=Depends(require('knowledge:write', 'im:content:read'))):
with errors():
return store.configure_job(single(principal, account_id), job_id, body.model_dump(), principal.id, client_ip(request))
@app.get("/api/v2/knowledge/jobs")''')
edit('knowledge_api.py', 'principal=Depends(require("knowledge:write"))', 'principal=Depends(require("knowledge:write", "im:content:read"))')
edit('knowledge_api.py', '"knowledge:write" if action == "restore" else "knowledge:review")', '"knowledge:write" if action in {"restore", "delete"} else "knowledge:review")')
edit('knowledge_api.py', ' if action == "publish":', ''' if action == 'delete':
if not body.confirmed:
raise ValueError('请确认删除已驳回知识,原始聊天归档会保留')
return store.delete_rejected(tenant, item_id, body.revision, principal.id, client_ip(request))
if action == "publish":''')