feat: 新增模型管理和供应商配置功能

### v1.1.0
- #### Added
  - 新增 AI 笔记风格选择
  - 新增 AI 笔记返回格式选择
  - 添加 AI 自定义笔记备注 Prompt
  - 添加任务失败重试
  - 添加全局设置页,可在设置页进行模型设置

- #### Optimize
  - 优化前端样式,优化用户体验
  - 增加生成中间产物,可用于失败后加快生成速度
- #### Fix
  - 修复视频截图视频过早删除错误
This commit is contained in:
思诺特
2025-04-26 23:40:17 +08:00
parent 1323cfd1ec
commit 171dea5e0d
51 changed files with 2511 additions and 414 deletions

View File

@@ -9,5 +9,5 @@ from app.models.model_config import ModelConfig
class GPTFactory:
@staticmethod
def from_config(config: ModelConfig) -> GPT:
client = OpenAICompatibleProvider(api_key=config.api_key, base_url=config.base_url).get_client()
client = OpenAICompatibleProvider(api_key=config.api_key, base_url=config.base_url).get_client
return UniversalGPT(client=client, model=config.model_name)

View File

@@ -0,0 +1,100 @@
from app.gpt.prompt import BASE_PROMPT
note_formats = [
{'label': '目录', 'value': 'toc'},
{'label': '原片跳转', 'value': 'link'},
{'label': '原片截图', 'value': 'screenshot'},
{'label': 'AI总结', 'value': 'summary'}
]
note_styles = [
{'label': '精简', 'value': 'minimal'},
{'label': '详细', 'value': 'detailed'},
{'label': '学术', 'value': 'academic'},
{"label": '教程',"value": 'tutorial', },
{'label': '小红书', 'value': 'xiaohongshu'},
{'label': '生活向', 'value': 'life_journal'},
{'label': '任务导向', 'value': 'task_oriented'},
{'label': '商业风格', 'value': 'business'},
{'label': '会议纪要', 'value': 'meeting_minutes'}
]
# 生成 BASE_PROMPT 函数
def generate_base_prompt(title, segment_text, tags, _format=None, style=None, extras=None):
# 生成 Base Prompt 开头部分
prompt = BASE_PROMPT.format(
video_title=title,
segment_text=segment_text,
tags=tags
)
# 添加用户选择的格式
if _format:
prompt += "\n" + "\n".join([get_format_function(f) for f in _format])
# 根据用户选择的笔记风格添加描述
if style:
prompt += "\n" + get_style_format(style)
# 添加额外内容
if extras:
prompt += f"\n{extras}"
return prompt
# 获取格式函数
def get_format_function(format_type):
format_map = {
'toc': get_toc_format,
'link': get_link_format,
'screenshot': get_screenshot_format,
'summary': get_summary_format
}
return format_map.get(format_type, lambda: '')()
# 风格描述的处理
def get_style_format(style):
style_map = {
'minimal': '1. **精简信息**: 仅记录最重要的内容,简洁明了。',
'detailed': '2. **详细记录**: 包含完整的时间戳和每个部分的详细讨论。',
'academic': '3. **学术风格**: 适合学术报告,正式且结构化。',
'xiaohongshu': '4. **小红书风格**: 适合社交平台分享,亲切、口语化。',
'life_journal': '5. **生活向**: 记录个人生活感悟,情感化表达。',
'task_oriented': '6. **任务导向**: 强调任务、目标,适合工作和待办事项。',
'business': '7. **商业风格**: 适合商业报告、会议纪要,正式且精准。',
'meeting_minutes': '8. **会议纪要**: 适合商业报告、会议纪要,正式且精准。',
"tutorial":"9.**教程笔记**:尽可能详细的记录教程,特别是关键点和一些重要的结论步骤"
}
return style_map.get(style, '')
# 格式化输出内容
def get_toc_format():
return '''
9. **目录**: 自动生成一个基于 `##` 级标题的目录。不需要插入原片跳转
'''
def get_link_format():
return '''
10. **原片跳转**: 为每个主要章节添加时间戳,使用格式 `*Content-[mm:ss]`。
重要:**始终**在章节标题前加上 `*Content` 前缀,例如:`AI 的发展史 *Content-[01:23]`。一定是标题在前 插入标记在后
'''
def get_screenshot_format():
return '''
11. **原片截图**: 如果某个部分涉及**视觉演示**或任何能帮助理解的内容,插入截图提示:
- 格式:`*Screenshot-[mm:ss]`
至少插入 1-3张截图
'''
def get_summary_format():
return '''
12. **AI总结**: 在笔记末尾加入简短的AI生成总结,并且二级标题 就是 AI 总结 例如 ## AI 总结。
'''

View File

@@ -1,4 +1,5 @@
from app.gpt.base import GPT
from app.gpt.prompt_builder import generate_base_prompt
from app.models.gpt_model import GPTSource
from app.gpt.prompt import BASE_PROMPT, AI_SUM, SCREENSHOT, LINK
from app.gpt.utils import fix_markdown
@@ -28,29 +29,35 @@ class UniversalGPT(GPT):
return [TranscriptSegment(**seg) if isinstance(seg, dict) else seg for seg in segments]
def create_messages(self, segments: List[TranscriptSegment],**kwargs):
content = BASE_PROMPT.format(
video_title=kwargs.get('title'),
print("UniversalGPT",kwargs)
content =generate_base_prompt(
title=kwargs.get('title'),
segment_text=self._build_segment_text(segments),
tags=kwargs.get('tags')
tags=kwargs.get('tags'),
_format=kwargs.get('_format'),
style=kwargs.get('style'),
extras=kwargs.get('extras')
)
if self.screenshot:
print(":需要截图")
content += SCREENSHOT
if self.link:
print(":需要链接")
content += LINK
print(content)
return [{"role": "user", "content": content + AI_SUM}]
return [{"role": "user", "content": content }]
def list_models(self):
return self.client.list_models()
return self.client.models.list()
def summarize(self, source: GPTSource) -> str:
self.screenshot = source.screenshot
self.link = source.link
source.segment = self.ensure_segments_type(source.segment)
messages = self.create_messages(source.segment, source.title,source.tags)
response = self.client.chat(
messages = self.create_messages(
source.segment,
title=source.title,
tags=source.tags
,
_format=source._format,
style=source.style,
extras=source.extras
)
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
temperature=0.7