This commit is contained in:
parent
d37517abb1
commit
65e99d7a53
|
|
@ -25,5 +25,3 @@ DEEPSEEK_V4_FLASH_RESPONSE_MODEL = OpenAIResponsesModel(
|
|||
api_key="sk-D9Y1mCe8VlvNqLuSC4mAjqEwxJ2nW4C0h8a7EPn8kg9RLsHq",
|
||||
),
|
||||
)
|
||||
|
||||
"sk-4a79ec5c0af74680997ef56758604850"
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
"""
|
||||
智能体运行时模块
|
||||
"""
|
||||
from asyncio import Queue, Task, Event, Lock
|
||||
from asyncio import Queue, Task, Event, Lock, create_task
|
||||
from typing import AsyncGenerator, Optional
|
||||
|
||||
|
||||
|
|
@ -11,79 +11,114 @@ from pydantic_ai.messages import AgentStreamEvent
|
|||
from pydantic_ai.run import AgentRunResultEvent
|
||||
from pydantic import BaseModel, Field
|
||||
from application.states.models import CapabilityComponentType
|
||||
from pydantic_ai import DeferredToolRequests, DeferredToolResults, ToolApproved
|
||||
|
||||
|
||||
class TaskRuntime(BaseModel):
|
||||
queue: Queue[AgentStreamEvent | AgentRunResultEvent | None] = Field(
|
||||
default_factory=lambda: Queue(maxsize=256), description="任务运行时队列"
|
||||
from pydantic_ai import (
|
||||
DeferredToolRequests,
|
||||
DeferredToolResults,
|
||||
ToolApproved,
|
||||
Agent,
|
||||
ModelMessage,
|
||||
ModelMessagesTypeAdapter,
|
||||
)
|
||||
worker: Task | None = Field(default=None, description="任务运行时工作器")
|
||||
done: Event = Field(default_factory=Event, description="任务运行时完成状态")
|
||||
from pydantic_ai.models.openai import OpenAIChatModel, OpenAIResponsesModel
|
||||
from pydantic_ai.providers.openai import OpenAIProvider
|
||||
from aiosqlite import connect, Row
|
||||
from pathlib import Path
|
||||
|
||||
# 构建数据库路径
|
||||
DATABASE_PATH = Path(__file__).parent.parent / "database.db"
|
||||
|
||||
|
||||
class TaskRuntimeRegistrar:
|
||||
async def get_message_history(task_id: str) -> list[ModelMessage]:
|
||||
"""
|
||||
任务运行时注册器
|
||||
获取消息历史
|
||||
"""
|
||||
async with connect(DATABASE_PATH) as connection:
|
||||
# 设置为行模式
|
||||
connection.row_factory = Row
|
||||
cursor = await connection.execute(
|
||||
"SELECT new_messages FROM message_history WHERE task_id = ? ORDER BY id ASC",
|
||||
(task_id,),
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
message_history: list[ModelMessage] = []
|
||||
for row in rows:
|
||||
new_messages = ModelMessagesTypeAdapter.validate_json(row["new_messages"])
|
||||
message_history.extend(new_messages)
|
||||
return message_history
|
||||
|
||||
|
||||
class Runtime(BaseModel):
|
||||
|
||||
task: Task | None = Field(default=None, description="运行时任务")
|
||||
event: Event = Field(default_factory=Event, description="运行时通知信号")
|
||||
queue: Queue[AgentStreamEvent | AgentRunResultEvent | None] = Field(
|
||||
default_factory=lambda: Queue(maxsize=256),
|
||||
description="运行时队列,默认最大长度为256",
|
||||
)
|
||||
|
||||
|
||||
class Deps(BaseModel):
|
||||
"""
|
||||
依赖类
|
||||
"""
|
||||
|
||||
...
|
||||
|
||||
|
||||
instruction = """
|
||||
# 角色
|
||||
专业友好AI助手,结构化解答各类问题。
|
||||
|
||||
# 输出硬性规则
|
||||
1. 全文强制标准Markdown,禁止纯文本;不要额外说明排版格式,直接输出内容;
|
||||
2. 层级使用 `#/##/###`,列表用 `-` 无序列表或数字有序列表;
|
||||
3. 代码块用 ```语言名``` 包裹;
|
||||
4. 重点内容标注 **粗体**/*斜体*;
|
||||
5. 思考、工具日志仅输出文本,适配前端折叠面板,禁止输出HTML标签;
|
||||
6. 内容分点拆分,排版整洁适配前端Markdown渲染。
|
||||
|
||||
# 行文要求
|
||||
语言通俗,逻辑完整简洁,无多余废话。
|
||||
"""
|
||||
|
||||
|
||||
class RuntimeManager:
|
||||
"""
|
||||
运行时管理器
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# 异步互斥锁
|
||||
self.lock = Lock()
|
||||
# 任务运行时字典,键为任务唯一标识,值为任务运行时实例
|
||||
self.task_runtimes: dict[str, TaskRuntime] = {}
|
||||
# 运行时字典,键为任务唯一标识,值为运行时实例
|
||||
self.runtimes: dict[str, Runtime] = {}
|
||||
|
||||
async def get(self, task_id: str) -> TaskRuntime:
|
||||
"""
|
||||
获取任务运行时实例
|
||||
:param task_id: 任务唯一标识
|
||||
:return: 任务运行时实例
|
||||
"""
|
||||
async with self.lock:
|
||||
# 若任务唯一标识不存在则创建任务运行时实例
|
||||
if task_id not in self.task_runtimes:
|
||||
self.task_runtimes[task_id] = TaskRuntime()
|
||||
return self.task_runtimes[task_id]
|
||||
|
||||
async def cancel(self, task_id: str):
|
||||
"""
|
||||
取消任务运行时实例
|
||||
:param task_id: 任务唯一标识
|
||||
"""
|
||||
async with self.lock:
|
||||
task_runtime = self.task_runtimes.pop(task_id, None)
|
||||
if task_runtime and task_runtime.worker and not task_runtime.worker.done():
|
||||
task_runtime.worker.cancel()
|
||||
|
||||
|
||||
async def worker(
|
||||
async def create(
|
||||
self,
|
||||
task_id: str,
|
||||
user_prompt: str | None,
|
||||
message_history,
|
||||
usage,
|
||||
capability_component_type: CapabilityComponentType,
|
||||
queue: Queue,
|
||||
deps=None,
|
||||
deferred_tool_results: DeferredToolResults | None = None,
|
||||
user_prompt: str | None,
|
||||
) -> Runtime:
|
||||
"""
|
||||
创建运行时实例
|
||||
:param task_id: 任务唯一标识
|
||||
:param capability_component_type: 能力组件类型
|
||||
:param user_prompt: 用户提示词
|
||||
:return: 运行时实例
|
||||
"""
|
||||
|
||||
async def run(
|
||||
capability_component_type: CapabilityComponentType,
|
||||
user_prompt: str | None,
|
||||
usage: dict,
|
||||
queue: Queue[AgentStreamEvent | AgentRunResultEvent | None],
|
||||
):
|
||||
"""
|
||||
工作器
|
||||
运行
|
||||
"""
|
||||
try:
|
||||
# 根据能力组件的类型匹配流式输出方法
|
||||
match capability_component_type:
|
||||
case CapabilityComponentType.TALK:
|
||||
from application.agent.talk import (
|
||||
run_stream_events,
|
||||
)
|
||||
|
||||
# 运行并流式输出事件
|
||||
stream_events = run_stream_events(
|
||||
user_prompt=user_prompt,
|
||||
message_history=message_history,
|
||||
usage=usage,
|
||||
)
|
||||
|
||||
# 预定航班
|
||||
case CapabilityComponentType.BOOK_FLIGHT:
|
||||
from application.agent.book_flight import (
|
||||
|
|
@ -146,10 +181,57 @@ async def worker(
|
|||
usage=usage,
|
||||
)
|
||||
|
||||
async for event in stream_events:
|
||||
# 兜底:闲聊
|
||||
case _:
|
||||
...
|
||||
|
||||
# 初始化智能体
|
||||
agent = Agent(
|
||||
model=OpenAIResponsesModel(
|
||||
model_name="deepseek/deepseek-flash",
|
||||
provider=OpenAIProvider(
|
||||
base_url="https://tokenhub.tencentmaas.com/v1",
|
||||
api_key="sk-D9Y1mCe8VlvNqLuSC4mAjqEwxJ2nW4C0h8a7EPn8kg9RLsHq",
|
||||
),
|
||||
),
|
||||
instructions=instruction,
|
||||
)
|
||||
async with agent.run_stream_events(
|
||||
user_prompt=user_prompt,
|
||||
message_history=await get_message_history(task_id),
|
||||
usage=usage,
|
||||
) as events:
|
||||
async for event in events:
|
||||
# 将事件放进队列
|
||||
await queue.put(event)
|
||||
# 哨兵:正常结束
|
||||
await queue.put(None)
|
||||
except Exception as e:
|
||||
# 异常丢入队列给消费端处理
|
||||
await queue.put(e)
|
||||
|
||||
except Exception as exception:
|
||||
await queue.put(exception)
|
||||
|
||||
async with self.lock:
|
||||
# 若任务唯一标识不存在则创建任务运行时实例
|
||||
if task_id not in self.runtimes:
|
||||
self.runtimes[task_id] = (runtime := Runtime())
|
||||
runtime.task = create_task(
|
||||
run(
|
||||
capability_component_type=capability_component_type,
|
||||
user_prompt=user_prompt,
|
||||
message_history=message_history,
|
||||
usage=usage,
|
||||
queue=runtime.queue,
|
||||
)
|
||||
)
|
||||
|
||||
return self.runtimes[task_id]
|
||||
|
||||
async def cancel(self, task_id: str):
|
||||
"""
|
||||
取消运行时实例
|
||||
:param task_id: 任务唯一标识
|
||||
"""
|
||||
async with self.lock:
|
||||
runtime = self.runtimes.pop(task_id, None)
|
||||
if runtime and runtime.task and not runtime.task.done():
|
||||
runtime.task.cancel()
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -8,7 +8,6 @@ import hashlib
|
|||
import json
|
||||
from pathlib import Path
|
||||
from random import choice
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from pyJianYingDraft import DraftFolder, VideoMaterial
|
||||
|
|
@ -86,7 +85,8 @@ DRAFT_GENERATE_SCHEMES = {
|
|||
{
|
||||
"clip_settings": [
|
||||
{
|
||||
"rotation": 90,
|
||||
"scale_x": 1.0,
|
||||
"scale_y": 1.0,
|
||||
},
|
||||
], # 剪辑设置
|
||||
},
|
||||
|
|
@ -98,7 +98,8 @@ DRAFT_GENERATE_SCHEMES = {
|
|||
{
|
||||
"clip_settings": [
|
||||
{
|
||||
"rotation": 90,
|
||||
"scale_x": 1.0,
|
||||
"scale_y": 1.0,
|
||||
},
|
||||
], # 剪辑设置
|
||||
},
|
||||
|
|
@ -126,13 +127,13 @@ class DraftsManager:
|
|||
|
||||
# 项目名称
|
||||
self.project_name = project_name
|
||||
|
||||
# 草稿生成方案
|
||||
self.draft_generate_scheme: list[list[tuple[str, dict]]] = (
|
||||
DRAFT_GENERATE_SCHEMES.get(self.project_name, [])
|
||||
)
|
||||
if not self.draft_generate_scheme:
|
||||
raise RuntimeError(f"未就 {self.project_name} 配置草稿生成方案")
|
||||
|
||||
# 构建此项目素材仓库路径
|
||||
self.material_vault_path = Path(rf"E:\jianying\materials\{project_name}")
|
||||
# 检查此项目素材仓库是否存在,若不存在则抛出异常
|
||||
|
|
@ -196,15 +197,10 @@ class DraftsManager:
|
|||
def batch_create(
|
||||
self,
|
||||
draft_counts: int,
|
||||
video_width: int = 1080,
|
||||
video_height: int = 1920,
|
||||
video_fps: int = 30,
|
||||
) -> None:
|
||||
"""
|
||||
批量创建草稿
|
||||
:param draft_counts: 草稿数
|
||||
:param video_width: 视频宽度(单位为像素),默认为 1080
|
||||
:param video_height: 视频高度(单位为像素),默认为 1920
|
||||
:param video_fps: 视频帧率(单位为帧/秒),默认为 30
|
||||
:return: 无
|
||||
"""
|
||||
|
|
@ -268,6 +264,11 @@ class DraftsManager:
|
|||
|
||||
print(f"正在创建草稿 {draft_name}({index}/{draft_counts})...")
|
||||
|
||||
if "横版" in self.project_name:
|
||||
video_width, video_height = 1920, 1080
|
||||
else:
|
||||
video_width, video_height = 1080, 1920
|
||||
|
||||
# 创建剪映草稿
|
||||
draft = Drafts(
|
||||
materials_vault_path=self.material_vault_path,
|
||||
|
|
@ -275,7 +276,7 @@ class DraftsManager:
|
|||
draft_name=draft_name,
|
||||
video_width=video_width,
|
||||
video_height=video_height,
|
||||
video_fps=video_fps,
|
||||
video_fps=30, # 视频帧率(单位为帧/秒),默认为 30
|
||||
video_duration=video_duration,
|
||||
)
|
||||
for segment_generate_scheme in draft_generate_scheme:
|
||||
|
|
|
|||
Loading…
Reference in New Issue