图片识别
This commit is contained in:
@@ -249,10 +249,10 @@ class AiChatController(http.Controller):
|
||||
ocr_error = ''
|
||||
if provider and provider.ocr_enabled:
|
||||
from ..models.ocr_provider import get_ocr_instance
|
||||
ocr = get_ocr_instance(provider)
|
||||
ocr, init_err = get_ocr_instance(provider)
|
||||
if ocr is None:
|
||||
ocr_error = 'OCR 实例创建失败,请检查 SecretId/SecretKey 是否完整'
|
||||
_logger.error('[AI-OCR] get_ocr_instance 返回 None')
|
||||
ocr_error = init_err or 'OCR 实例创建失败'
|
||||
_logger.error('[AI-OCR] get_ocr_instance 失败: %s', ocr_error)
|
||||
else:
|
||||
result = ocr.smart_recognize(raw_bytes, mimetype)
|
||||
if result.get('success'):
|
||||
|
||||
@@ -146,21 +146,28 @@ def get_ocr_instance(provider):
|
||||
"""从 AiProvider 记录中创建 OCR 实例。
|
||||
|
||||
:param provider: ai.provider 记录
|
||||
:return: TencentOCR 实例或 None
|
||||
:return: (TencentOCR 实例 | None, str 错误原因)
|
||||
"""
|
||||
if not provider.ocr_enabled:
|
||||
return None
|
||||
if not provider.ocr_secret_id or not provider.ocr_secret_key:
|
||||
_logger.warning('OCR 已启用但 SecretId/SecretKey 未配置 (provider=%s)', provider.name)
|
||||
return None
|
||||
return None, 'OCR 未启用'
|
||||
|
||||
# 逐项校验,给出精确的错误信息
|
||||
if not provider.ocr_secret_id:
|
||||
return None, '未配置 SecretId(请到服务商配置 → OCR配置 填写)'
|
||||
if not provider.ocr_secret_key:
|
||||
return None, '未配置 SecretKey(请到服务商配置 → OCR配置 填写)'
|
||||
if not HAS_TENCENT_SDK:
|
||||
return None
|
||||
return None, 'tencentcloud-sdk-python 未安装(pip install tencentcloud-sdk-python)'
|
||||
|
||||
try:
|
||||
return TencentOCR(
|
||||
secret_id=provider.ocr_secret_id,
|
||||
secret_key=provider.ocr_secret_key,
|
||||
region=provider.ocr_region or 'ap-guangzhou',
|
||||
)
|
||||
), ''
|
||||
except ValueError as ve:
|
||||
_logger.warning('[AI-OCR] 参数错误: %s', ve)
|
||||
return None, str(ve)
|
||||
except Exception as e:
|
||||
_logger.exception('创建 OCR 实例失败')
|
||||
return None
|
||||
_logger.exception('[AI-OCR] 创建 OCR 实例异常')
|
||||
return None, f'初始化异常: {e}'
|
||||
|
||||
@@ -35,17 +35,7 @@ export class AiChatAction extends Component {
|
||||
.replace(/【附件:[^】]+】[\s\S]*?--- 附件内容结束 ---/g, '')
|
||||
.replace(/\[附件[::]\s*[^\]]+\]\n?/g, '')
|
||||
.trim() || safe;
|
||||
// URL → 精美卡片(还原 escapeHtml 把 & 变回 &,保证 href 正确)
|
||||
display = display.replace(
|
||||
/(https?:\/\/[^\s<>"'\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]+)/g,
|
||||
(url) => {
|
||||
const rawUrl = url.replace(/&/g, '&');
|
||||
let domain = '';
|
||||
try { domain = new URL(rawUrl).hostname; } catch (_) { domain = rawUrl.substring(0, 50); }
|
||||
const displayUrl = rawUrl.length > 60 ? rawUrl.substring(0, 57) + '...' : rawUrl;
|
||||
return `<a class="o_ai_link_card" href="${rawUrl}" target="_blank" rel="noopener noreferrer" title="${rawUrl}"><span class="o_ai_link_icon"><i class="fa fa-external-link"></i></span><span class="o_ai_link_domain">${this._escapeHtml(domain)}</span><span class="o_ai_link_url">${this._escapeHtml(displayUrl)}</span></a>`;
|
||||
}
|
||||
);
|
||||
// 不做额外处理,URL 保持纯文本显示
|
||||
return display.replace(/\n/g, '<br>');
|
||||
}
|
||||
|
||||
|
||||
@@ -235,22 +235,7 @@ function renderContent(text) {
|
||||
.replace(/【附件:[^】]+】[\s\S]*?--- 附件内容结束 ---/g, '')
|
||||
.replace(/\[附件[::]\s*[^\]]+\]\n?/g, '')
|
||||
.trim() || safe; // 若 strip 后为空,回退到 safe 继续处理 URL
|
||||
// URL 渲染为精美卡片(先还原 escapeHtml 把 & 变回 &,保证 href 正确)
|
||||
display = display.replace(
|
||||
/(https?:\/\/[^\s<>"'\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]+)/g,
|
||||
(url) => {
|
||||
// 还原 HTML 实体(escapeHtml 会把 & 变成 &,URL 参数中的 & 需要还原)
|
||||
const rawUrl = url.replace(/&/g, '&');
|
||||
let domain = '';
|
||||
try {
|
||||
domain = new URL(rawUrl).hostname;
|
||||
} catch (_) {
|
||||
domain = rawUrl.substring(0, 50);
|
||||
}
|
||||
const displayUrl = rawUrl.length > 60 ? rawUrl.substring(0, 57) + '...' : rawUrl;
|
||||
return `<a class="o_ai_link_card" href="${rawUrl}" target="_blank" rel="noopener noreferrer" title="${rawUrl}"><span class="o_ai_link_icon"><i class="fa fa-external-link"></i></span><span class="o_ai_link_domain">${escapeHtml(domain)}</span><span class="o_ai_link_url">${escapeHtml(displayUrl)}</span></a>`;
|
||||
}
|
||||
);
|
||||
// 不做额外处理,URL 保持纯文本显示
|
||||
// 换行转 <br>
|
||||
display = display.replace(/\n/g, '<br>');
|
||||
return display;
|
||||
|
||||
Reference in New Issue
Block a user