Merge branch 'feat/docker-release-electron-sync' of github.com:presenton/presenton into feat/docker-release-electron-sync
This commit is contained in:
commit
7c96044688
20 changed files with 1168 additions and 24 deletions
|
|
@ -214,6 +214,15 @@ These settings apply to both Docker and the Electron app's backend. You may want
|
|||
- TOOL_CALLS=[Enable/Disable Tool Calls on Custom LLM]: If **true**, **LLM** will use Tool Call instead of Json Schema for Structured Output.
|
||||
- DISABLE_THINKING=[Enable/Disable Thinking on Custom LLM]: If **true**, Thinking will be disabled.
|
||||
- WEB_GROUNDING=[Enable/Disable Web Search for OpenAI, Google And Anthropic]: If **true**, LLM will be able to search web for better results.
|
||||
- MEM0_ENABLED=[true/false]: Enables mem0 OSS presentation memory. Default is **true**.
|
||||
- MEM0_DIR=[Path]: Directory for mem0 OSS local storage (Qdrant path + history DB). Default is **/app_data/mem0**.
|
||||
- MEM0_EMBEDDER_PROVIDER=[Provider]: Embedder provider for mem0 OSS. Default is **fastembed**.
|
||||
- MEM0_EMBEDDER_MODEL=[Model]: Mid-range local embedding model for memory search. Default is **BAAI/bge-small-en-v1.5**.
|
||||
- MEM0_EMBEDDING_DIMS=[Number]: Embedding dimensions used by mem0 embedder and qdrant collection. Default is **384**.
|
||||
- LITEPARSE_DPI=[Number]: LiteParse OCR render DPI (higher can increase memory use). Default is **120**.
|
||||
- LITEPARSE_NUM_WORKERS=[Number]: LiteParse OCR worker count. Default is **1** for stable Docker parsing.
|
||||
|
||||
Mem0 in Docker uses OSS/self-hosted mode (not Mem0 Platform API). Memory is isolated per presentation ID. Prompt context, extracted document text, generated outline context, and subsequent edit interactions are stored and retrieved only for that same presentation (including when revisiting later).
|
||||
|
||||
You can also set the following environment variables to customize the image generation provider and API keys:
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,13 @@ services:
|
|||
- DISABLE_ANONYMOUS_TRACKING=${DISABLE_ANONYMOUS_TRACKING}
|
||||
- COMFYUI_URL=${COMFYUI_URL}
|
||||
- COMFYUI_WORKFLOW=${COMFYUI_WORKFLOW}
|
||||
- MEM0_ENABLED=${MEM0_ENABLED:-true}
|
||||
- MEM0_DIR=${MEM0_DIR:-/app_data/mem0}
|
||||
- MEM0_EMBEDDER_PROVIDER=${MEM0_EMBEDDER_PROVIDER:-fastembed}
|
||||
- MEM0_EMBEDDER_MODEL=${MEM0_EMBEDDER_MODEL:-BAAI/bge-small-en-v1.5}
|
||||
- MEM0_EMBEDDING_DIMS=${MEM0_EMBEDDING_DIMS:-384}
|
||||
- LITEPARSE_DPI=${LITEPARSE_DPI:-120}
|
||||
- LITEPARSE_NUM_WORKERS=${LITEPARSE_NUM_WORKERS:-1}
|
||||
|
||||
production-gpu:
|
||||
# image: ghcr.io/presenton/presenton:latest
|
||||
|
|
@ -81,6 +88,13 @@ services:
|
|||
- DISABLE_ANONYMOUS_TRACKING=${DISABLE_ANONYMOUS_TRACKING}
|
||||
- COMFYUI_URL=${COMFYUI_URL}
|
||||
- COMFYUI_WORKFLOW=${COMFYUI_WORKFLOW}
|
||||
- MEM0_ENABLED=${MEM0_ENABLED:-true}
|
||||
- MEM0_DIR=${MEM0_DIR:-/app_data/mem0}
|
||||
- MEM0_EMBEDDER_PROVIDER=${MEM0_EMBEDDER_PROVIDER:-fastembed}
|
||||
- MEM0_EMBEDDER_MODEL=${MEM0_EMBEDDER_MODEL:-BAAI/bge-small-en-v1.5}
|
||||
- MEM0_EMBEDDING_DIMS=${MEM0_EMBEDDING_DIMS:-384}
|
||||
- LITEPARSE_DPI=${LITEPARSE_DPI:-120}
|
||||
- LITEPARSE_NUM_WORKERS=${LITEPARSE_NUM_WORKERS:-1}
|
||||
|
||||
development:
|
||||
build:
|
||||
|
|
@ -122,6 +136,13 @@ services:
|
|||
- DISABLE_ANONYMOUS_TRACKING=${DISABLE_ANONYMOUS_TRACKING}
|
||||
- COMFYUI_URL=${COMFYUI_URL}
|
||||
- COMFYUI_WORKFLOW=${COMFYUI_WORKFLOW}
|
||||
- MEM0_ENABLED=${MEM0_ENABLED:-true}
|
||||
- MEM0_DIR=${MEM0_DIR:-/app_data/mem0}
|
||||
- MEM0_EMBEDDER_PROVIDER=${MEM0_EMBEDDER_PROVIDER:-fastembed}
|
||||
- MEM0_EMBEDDER_MODEL=${MEM0_EMBEDDER_MODEL:-BAAI/bge-small-en-v1.5}
|
||||
- MEM0_EMBEDDING_DIMS=${MEM0_EMBEDDING_DIMS:-384}
|
||||
- LITEPARSE_DPI=${LITEPARSE_DPI:-120}
|
||||
- LITEPARSE_NUM_WORKERS=${LITEPARSE_NUM_WORKERS:-1}
|
||||
|
||||
development-gpu:
|
||||
build:
|
||||
|
|
@ -169,6 +190,13 @@ services:
|
|||
- DISABLE_ANONYMOUS_TRACKING=${DISABLE_ANONYMOUS_TRACKING}
|
||||
- COMFYUI_URL=${COMFYUI_URL}
|
||||
- COMFYUI_WORKFLOW=${COMFYUI_WORKFLOW}
|
||||
- MEM0_ENABLED=${MEM0_ENABLED:-true}
|
||||
- MEM0_DIR=${MEM0_DIR:-/app_data/mem0}
|
||||
- MEM0_EMBEDDER_PROVIDER=${MEM0_EMBEDDER_PROVIDER:-fastembed}
|
||||
- MEM0_EMBEDDER_MODEL=${MEM0_EMBEDDER_MODEL:-BAAI/bge-small-en-v1.5}
|
||||
- MEM0_EMBEDDING_DIMS=${MEM0_EMBEDDING_DIMS:-384}
|
||||
- LITEPARSE_DPI=${LITEPARSE_DPI:-120}
|
||||
- LITEPARSE_NUM_WORKERS=${LITEPARSE_NUM_WORKERS:-1}
|
||||
|
||||
volumes:
|
||||
presenton_root_node_modules:
|
||||
|
|
|
|||
|
|
@ -4,4 +4,4 @@ OPENAI_URL = "https://api.openai.com/v1"
|
|||
DEFAULT_OPENAI_MODEL = "gpt-4.1"
|
||||
DEFAULT_GOOGLE_MODEL = "models/gemini-2.5-flash"
|
||||
DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-4-20250514"
|
||||
DEFAULT_CODEX_MODEL = "gpt-5.1-codex-mini"
|
||||
DEFAULT_CODEX_MODEL = "gpt-5.2"
|
||||
|
|
|
|||
|
|
@ -52,10 +52,9 @@ const CHATGPT_MODELS: CodexModel[] = [
|
|||
{ id: "gpt-5.4-mini", name: "GPT-5.4-Mini" },
|
||||
{ id: "gpt-5.3-codex", name: "GPT-5.3-Codex" },
|
||||
{ id: "gpt-5.2", name: "GPT-5.2" },
|
||||
{ id: "gpt-5.1-codex-mini", name: "GPT-5.1-Codex-Mini" },
|
||||
];
|
||||
|
||||
const DEFAULT_CODEX_MODEL = "gpt-5.1-codex-mini";
|
||||
const DEFAULT_CODEX_MODEL = "gpt-5.2";
|
||||
|
||||
export default function CodexConfig({
|
||||
codexModel,
|
||||
|
|
|
|||
|
|
@ -39,10 +39,9 @@ export const CHATGPT_MODELS: CodexModel[] = [
|
|||
{ id: "gpt-5.4-mini", name: "GPT-5.4-Mini" },
|
||||
{ id: "gpt-5.3-codex", name: "GPT-5.3-Codex" },
|
||||
{ id: "gpt-5.2", name: "GPT-5.2" },
|
||||
{ id: "gpt-5.1-codex-mini", name: "GPT-5.1-Codex-Mini" },
|
||||
];
|
||||
|
||||
export const DEFAULT_CODEX_MODEL = "gpt-5.1-codex-mini";
|
||||
export const DEFAULT_CODEX_MODEL = "gpt-5.2";
|
||||
|
||||
export default function CodexConfig({
|
||||
codexModel,
|
||||
|
|
|
|||
|
|
@ -18,11 +18,17 @@ from models.sse_response import (
|
|||
from services.temp_file_service import TEMP_FILE_SERVICE
|
||||
from services.database import get_async_session
|
||||
from services.documents_loader import DocumentsLoader
|
||||
from services.mem0_presentation_memory_service import (
|
||||
MEM0_PRESENTATION_MEMORY_SERVICE,
|
||||
)
|
||||
from utils.outline_utils import (
|
||||
get_no_of_outlines_to_generate_for_n_slides,
|
||||
get_presentation_title_from_presentation_outline,
|
||||
)
|
||||
from utils.llm_calls.generate_presentation_outlines import generate_ppt_outline
|
||||
from utils.llm_calls.generate_presentation_outlines import (
|
||||
generate_ppt_outline,
|
||||
get_messages as get_outline_messages,
|
||||
)
|
||||
|
||||
OUTLINES_ROUTER = APIRouter(prefix="/outlines", tags=["Outlines"])
|
||||
|
||||
|
|
@ -65,6 +71,34 @@ async def stream_outlines(
|
|||
else:
|
||||
n_slides_to_generate = None
|
||||
|
||||
outline_messages = get_outline_messages(
|
||||
presentation.content,
|
||||
n_slides_to_generate,
|
||||
presentation.language,
|
||||
additional_context,
|
||||
presentation.tone,
|
||||
presentation.verbosity,
|
||||
presentation.instructions,
|
||||
presentation.include_title_slide,
|
||||
presentation.include_table_of_contents,
|
||||
)
|
||||
await MEM0_PRESENTATION_MEMORY_SERVICE.store_generation_context(
|
||||
presentation_id=presentation.id,
|
||||
system_prompt=(
|
||||
outline_messages[0].content
|
||||
if len(outline_messages) > 0
|
||||
else None
|
||||
),
|
||||
user_prompt=(
|
||||
outline_messages[1].content
|
||||
if len(outline_messages) > 1
|
||||
else None
|
||||
),
|
||||
extracted_document_text=additional_context,
|
||||
source_content=presentation.content,
|
||||
instructions=presentation.instructions,
|
||||
)
|
||||
|
||||
async for chunk in generate_ppt_outline(
|
||||
presentation.content,
|
||||
n_slides_to_generate,
|
||||
|
|
@ -132,6 +166,11 @@ async def stream_outlines(
|
|||
sql_session.add(presentation)
|
||||
await sql_session.commit()
|
||||
|
||||
await MEM0_PRESENTATION_MEMORY_SERVICE.store_generated_outlines(
|
||||
presentation.id,
|
||||
presentation.outlines,
|
||||
)
|
||||
|
||||
yield SSECompleteResponse(
|
||||
key="presentation", value=presentation.model_dump(mode="json")
|
||||
).to_string()
|
||||
|
|
|
|||
|
|
@ -32,9 +32,15 @@ from models.sql.template import TemplateModel
|
|||
from services.documents_loader import DocumentsLoader
|
||||
from services.webhook_service import WebhookService
|
||||
from services.image_generation_service import ImageGenerationService
|
||||
from services.mem0_presentation_memory_service import (
|
||||
MEM0_PRESENTATION_MEMORY_SERVICE,
|
||||
)
|
||||
from utils.dict_utils import deep_update
|
||||
from utils.export_utils import export_presentation
|
||||
from utils.llm_calls.generate_presentation_outlines import generate_ppt_outline
|
||||
from utils.llm_calls.generate_presentation_outlines import (
|
||||
generate_ppt_outline,
|
||||
get_messages as get_outline_messages,
|
||||
)
|
||||
from models.sql.slide import SlideModel
|
||||
from models.sql.presentation_layout_code import PresentationLayoutCodeModel
|
||||
from models.sse_response import SSECompleteResponse, SSEErrorResponse, SSEResponse
|
||||
|
|
@ -320,6 +326,11 @@ async def prepare_presentation(
|
|||
presentation.set_structure(presentation_structure)
|
||||
await sql_session.commit()
|
||||
|
||||
await MEM0_PRESENTATION_MEMORY_SERVICE.store_generated_outlines(
|
||||
presentation.id,
|
||||
presentation.outlines,
|
||||
)
|
||||
|
||||
return presentation
|
||||
|
||||
|
||||
|
|
@ -606,14 +617,13 @@ async def generate_presentation_handler(
|
|||
try:
|
||||
using_slides_markdown = False
|
||||
language_to_use = (request.language or "").strip() or None
|
||||
additional_context = ""
|
||||
|
||||
if request.slides_markdown:
|
||||
using_slides_markdown = True
|
||||
request.n_slides = len(request.slides_markdown)
|
||||
|
||||
if not using_slides_markdown:
|
||||
additional_context = ""
|
||||
|
||||
# Updating async status
|
||||
if async_status:
|
||||
async_status.message = "Generating presentation outlines"
|
||||
|
|
@ -642,6 +652,34 @@ async def generate_presentation_handler(
|
|||
)
|
||||
)
|
||||
|
||||
outline_messages = get_outline_messages(
|
||||
request.content,
|
||||
n_slides_to_generate,
|
||||
language_to_use,
|
||||
additional_context,
|
||||
request.tone.value,
|
||||
request.verbosity.value,
|
||||
request.instructions,
|
||||
request.include_title_slide,
|
||||
request.include_table_of_contents,
|
||||
)
|
||||
await MEM0_PRESENTATION_MEMORY_SERVICE.store_generation_context(
|
||||
presentation_id=presentation_id,
|
||||
system_prompt=(
|
||||
outline_messages[0].content
|
||||
if len(outline_messages) > 0
|
||||
else None
|
||||
),
|
||||
user_prompt=(
|
||||
outline_messages[1].content
|
||||
if len(outline_messages) > 1
|
||||
else None
|
||||
),
|
||||
extracted_document_text=additional_context,
|
||||
source_content=request.content,
|
||||
instructions=request.instructions,
|
||||
)
|
||||
|
||||
presentation_outlines_text = ""
|
||||
async for chunk in generate_ppt_outline(
|
||||
request.content,
|
||||
|
|
@ -699,6 +737,20 @@ async def generate_presentation_handler(
|
|||
)
|
||||
total_outlines = len(request.slides_markdown)
|
||||
|
||||
await MEM0_PRESENTATION_MEMORY_SERVICE.store_generation_context(
|
||||
presentation_id=presentation_id,
|
||||
system_prompt=None,
|
||||
user_prompt=None,
|
||||
extracted_document_text=None,
|
||||
source_content=request.content,
|
||||
instructions=request.instructions,
|
||||
)
|
||||
|
||||
await MEM0_PRESENTATION_MEMORY_SERVICE.store_generated_outlines(
|
||||
presentation_id,
|
||||
presentation_outlines.model_dump(mode="json"),
|
||||
)
|
||||
|
||||
# Updating async status
|
||||
if async_status:
|
||||
async_status.message = "Selecting layout for each slide"
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ from models.sql.presentation import PresentationModel
|
|||
from models.sql.slide import SlideModel
|
||||
from services.database import get_async_session
|
||||
from services.image_generation_service import ImageGenerationService
|
||||
from services.mem0_presentation_memory_service import (
|
||||
MEM0_PRESENTATION_MEMORY_SERVICE,
|
||||
)
|
||||
from utils.asset_directory_utils import get_images_directory
|
||||
from utils.llm_calls.edit_slide import get_edited_slide_content
|
||||
from utils.llm_calls.edit_slide_html import get_edited_slide_html
|
||||
from utils.llm_calls.select_slide_type_on_edit import get_slide_layout_from_prompt
|
||||
from utils.process_slides import process_old_and_new_slides_and_fetch_assets
|
||||
import uuid
|
||||
|
||||
|
||||
SLIDE_ROUTER = APIRouter(prefix="/slide", tags=["Slide"])
|
||||
|
|
@ -31,13 +33,28 @@ async def edit_slide(
|
|||
if not presentation:
|
||||
raise HTTPException(status_code=404, detail="Presentation not found")
|
||||
|
||||
memory_context = await MEM0_PRESENTATION_MEMORY_SERVICE.retrieve_context(
|
||||
presentation.id,
|
||||
prompt,
|
||||
)
|
||||
|
||||
presentation_layout = presentation.get_layout()
|
||||
slide_layout = await get_slide_layout_from_prompt(
|
||||
prompt, presentation_layout, slide
|
||||
prompt,
|
||||
presentation_layout,
|
||||
slide,
|
||||
memory_context,
|
||||
)
|
||||
|
||||
edited_slide_content = await get_edited_slide_content(
|
||||
prompt, slide, presentation.language, slide_layout
|
||||
prompt,
|
||||
slide,
|
||||
presentation.language,
|
||||
slide_layout,
|
||||
presentation.tone,
|
||||
presentation.verbosity,
|
||||
presentation.instructions,
|
||||
memory_context,
|
||||
)
|
||||
|
||||
image_generation_service = ImageGenerationService(get_images_directory())
|
||||
|
|
@ -59,6 +76,13 @@ async def edit_slide(
|
|||
sql_session.add_all(new_assets)
|
||||
await sql_session.commit()
|
||||
|
||||
await MEM0_PRESENTATION_MEMORY_SERVICE.store_slide_edit(
|
||||
presentation_id=presentation.id,
|
||||
slide_index=slide.index,
|
||||
edit_prompt=prompt,
|
||||
edited_slide_content=edited_slide_content,
|
||||
)
|
||||
|
||||
return slide
|
||||
|
||||
|
||||
|
|
@ -73,11 +97,24 @@ async def edit_slide_html(
|
|||
if not slide:
|
||||
raise HTTPException(status_code=404, detail="Slide not found")
|
||||
|
||||
presentation = await sql_session.get(PresentationModel, slide.presentation)
|
||||
if not presentation:
|
||||
raise HTTPException(status_code=404, detail="Presentation not found")
|
||||
|
||||
html_to_edit = html or slide.html_content
|
||||
if not html_to_edit:
|
||||
raise HTTPException(status_code=400, detail="No HTML to edit")
|
||||
|
||||
edited_slide_html = await get_edited_slide_html(prompt, html_to_edit)
|
||||
memory_context = await MEM0_PRESENTATION_MEMORY_SERVICE.retrieve_context(
|
||||
presentation.id,
|
||||
prompt,
|
||||
)
|
||||
|
||||
edited_slide_html = await get_edited_slide_html(
|
||||
prompt,
|
||||
html_to_edit,
|
||||
memory_context,
|
||||
)
|
||||
|
||||
# Always assign a new unique id to the slide
|
||||
# This is to ensure that the nextjs can track slide updates
|
||||
|
|
@ -87,4 +124,11 @@ async def edit_slide_html(
|
|||
slide.html_content = edited_slide_html
|
||||
await sql_session.commit()
|
||||
|
||||
await MEM0_PRESENTATION_MEMORY_SERVICE.store_slide_edit(
|
||||
presentation_id=presentation.id,
|
||||
slide_index=slide.index,
|
||||
edit_prompt=prompt,
|
||||
edited_slide_content=edited_slide_html,
|
||||
)
|
||||
|
||||
return slide
|
||||
|
|
|
|||
|
|
@ -4,4 +4,4 @@ OPENAI_URL = "https://api.openai.com/v1"
|
|||
DEFAULT_OPENAI_MODEL = "gpt-4.1"
|
||||
DEFAULT_GOOGLE_MODEL = "models/gemini-2.5-flash"
|
||||
DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-4-20250514"
|
||||
DEFAULT_CODEX_MODEL = "gpt-5.1-codex-mini"
|
||||
DEFAULT_CODEX_MODEL = "gpt-5.2"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ dependencies = [
|
|||
"fastembed-vectorstore>=0.5.2",
|
||||
"fastmcp>=2.11.0",
|
||||
"google-genai>=1.28.0",
|
||||
"mem0ai[nlp]>=0.1.115",
|
||||
"nltk>=3.9.1",
|
||||
"openai>=1.98.0",
|
||||
"pathvalidate>=3.3.1",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ class LiteParseError(Exception):
|
|||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
_LOG_SNIPPET_LIMIT = 600
|
||||
_DEFAULT_DPI = 120
|
||||
_DEFAULT_NUM_WORKERS = 1
|
||||
|
||||
|
||||
def _snippet(value: str, limit: int = _LOG_SNIPPET_LIMIT) -> str:
|
||||
|
|
@ -36,10 +38,36 @@ def _subprocess_text_kwargs() -> Mapping[str, object]:
|
|||
return {"text": True, "encoding": "utf-8", "errors": "replace"}
|
||||
|
||||
|
||||
def _env_int(name: str, default: int, minimum: int, maximum: int) -> int:
|
||||
raw = (os.getenv(name) or "").strip()
|
||||
if not raw:
|
||||
return default
|
||||
|
||||
try:
|
||||
parsed = int(raw)
|
||||
except Exception:
|
||||
LOGGER.warning(
|
||||
"[LiteParse] Invalid %s=%r, using default=%s",
|
||||
name,
|
||||
raw,
|
||||
default,
|
||||
)
|
||||
return default
|
||||
|
||||
return min(max(parsed, minimum), maximum)
|
||||
|
||||
|
||||
class LiteParseService:
|
||||
def __init__(self, timeout_seconds: int = 180):
|
||||
self.timeout_seconds = timeout_seconds
|
||||
self.node_binary = os.getenv("LITEPARSE_NODE_BINARY", "node")
|
||||
self.dpi = _env_int("LITEPARSE_DPI", _DEFAULT_DPI, minimum=72, maximum=600)
|
||||
self.num_workers = _env_int(
|
||||
"LITEPARSE_NUM_WORKERS",
|
||||
_DEFAULT_NUM_WORKERS,
|
||||
minimum=1,
|
||||
maximum=64,
|
||||
)
|
||||
self.runner_path = os.getenv("LITEPARSE_RUNNER_PATH", self._resolve_runner_path())
|
||||
self.runner_dir = os.path.dirname(self.runner_path)
|
||||
self._npm_project_root = self._resolve_npm_project_root()
|
||||
|
|
@ -231,6 +259,10 @@ class LiteParseService:
|
|||
"true" if ocr_enabled else "false",
|
||||
"--ocr-language",
|
||||
ocr_language,
|
||||
"--dpi",
|
||||
str(self.dpi),
|
||||
"--num-workers",
|
||||
str(self.num_workers),
|
||||
]
|
||||
ocr_server = (os.getenv("LITEPARSE_OCR_SERVER_URL") or "").strip()
|
||||
if ocr_server:
|
||||
|
|
@ -240,10 +272,12 @@ class LiteParseService:
|
|||
command.extend(["--tessdata-path", tessdata])
|
||||
|
||||
LOGGER.info(
|
||||
"[LiteParse] Parsing file=%s ocr_enabled=%s ocr_language=%s",
|
||||
"[LiteParse] Parsing file=%s ocr_enabled=%s ocr_language=%s dpi=%s num_workers=%s",
|
||||
file_path,
|
||||
ocr_enabled,
|
||||
ocr_language,
|
||||
self.dpi,
|
||||
self.num_workers,
|
||||
)
|
||||
|
||||
process = subprocess.run(
|
||||
|
|
|
|||
291
servers/fastapi/services/mem0_presentation_memory_service.py
Normal file
291
servers/fastapi/services/mem0_presentation_memory_service.py
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from importlib import import_module
|
||||
from typing import Any, Optional
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Mem0PresentationMemoryService:
|
||||
def __init__(self):
|
||||
self._enabled = self._to_bool(os.getenv("MEM0_ENABLED"), default=True)
|
||||
self._top_k = self._to_int(os.getenv("MEM0_TOP_K"), default=8)
|
||||
self._max_context_chars = self._to_int(
|
||||
os.getenv("MEM0_MAX_CONTEXT_CHARS"), default=6000
|
||||
)
|
||||
self._namespace_prefix = (
|
||||
os.getenv("MEM0_PRESENTATION_NAMESPACE_PREFIX") or "presentation"
|
||||
).strip() or "presentation"
|
||||
|
||||
self._embedder_provider = (
|
||||
os.getenv("MEM0_EMBEDDER_PROVIDER") or "fastembed"
|
||||
).strip() or "fastembed"
|
||||
self._embedder_model = (
|
||||
os.getenv("MEM0_EMBEDDER_MODEL") or "BAAI/bge-small-en-v1.5"
|
||||
).strip() or "BAAI/bge-small-en-v1.5"
|
||||
self._embedding_dims = self._to_int(
|
||||
os.getenv("MEM0_EMBEDDING_DIMS"),
|
||||
default=384,
|
||||
)
|
||||
|
||||
app_data_dir = (os.getenv("APP_DATA_DIRECTORY") or "/tmp/presenton").strip()
|
||||
self._mem0_dir = (os.getenv("MEM0_DIR") or os.path.join(app_data_dir, "mem0")).strip()
|
||||
self._qdrant_path = (os.getenv("MEM0_QDRANT_PATH") or os.path.join(self._mem0_dir, "qdrant")).strip()
|
||||
self._history_db_path = (
|
||||
os.getenv("MEM0_HISTORY_DB_PATH")
|
||||
or os.path.join(self._mem0_dir, "history.db")
|
||||
).strip()
|
||||
self._collection_name = (
|
||||
os.getenv("MEM0_COLLECTION_NAME") or "presenton_memories"
|
||||
).strip() or "presenton_memories"
|
||||
|
||||
self._client: Any = None
|
||||
self._attempted_client_init = False
|
||||
|
||||
@staticmethod
|
||||
def _to_bool(value: Optional[str], default: bool = False) -> bool:
|
||||
if value is None:
|
||||
return default
|
||||
return str(value).strip().lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
@staticmethod
|
||||
def _to_int(value: Optional[str], default: int) -> int:
|
||||
try:
|
||||
parsed = int(value) if value is not None else default
|
||||
return max(1, parsed)
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
def _scope_user_id(self, presentation_id: UUID) -> str:
|
||||
return f"{self._namespace_prefix}:{presentation_id}"
|
||||
|
||||
def _truncate(self, text: str, limit: int = 20000) -> str:
|
||||
if len(text) <= limit:
|
||||
return text
|
||||
return f"{text[:limit]}\n\n[TRUNCATED]"
|
||||
|
||||
def _get_oss_config(self) -> dict:
|
||||
return {
|
||||
"vector_store": {
|
||||
"provider": "qdrant",
|
||||
"config": {
|
||||
"collection_name": self._collection_name,
|
||||
"path": self._qdrant_path,
|
||||
"on_disk": True,
|
||||
"embedding_model_dims": self._embedding_dims,
|
||||
},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": self._embedder_provider,
|
||||
"config": {
|
||||
"model": self._embedder_model,
|
||||
"embedding_dims": self._embedding_dims,
|
||||
},
|
||||
},
|
||||
"history_db_path": self._history_db_path,
|
||||
}
|
||||
|
||||
async def _get_client(self):
|
||||
if not self._enabled:
|
||||
return None
|
||||
|
||||
if self._client is not None:
|
||||
return self._client
|
||||
|
||||
if self._attempted_client_init:
|
||||
return None
|
||||
|
||||
self._attempted_client_init = True
|
||||
|
||||
try:
|
||||
module = import_module("mem0")
|
||||
memory_cls = getattr(module, "Memory")
|
||||
|
||||
os.makedirs(self._mem0_dir, exist_ok=True)
|
||||
os.makedirs(self._qdrant_path, exist_ok=True)
|
||||
|
||||
config = self._get_oss_config()
|
||||
|
||||
try:
|
||||
self._client = memory_cls.from_config(config)
|
||||
except Exception:
|
||||
# Backward compatibility across mem0 OSS versions.
|
||||
self._client = memory_cls(config)
|
||||
|
||||
LOGGER.info(
|
||||
"Mem0 OSS presentation memory service initialized (qdrant_path=%s, history_db_path=%s)",
|
||||
self._qdrant_path,
|
||||
self._history_db_path,
|
||||
)
|
||||
except Exception:
|
||||
LOGGER.exception("Failed to initialize Mem0 OSS Memory")
|
||||
self._client = None
|
||||
|
||||
return self._client
|
||||
|
||||
async def _add_message(self, presentation_id: UUID, message: str):
|
||||
client = await self._get_client()
|
||||
if client is None or not message.strip():
|
||||
return
|
||||
|
||||
scoped_user_id = self._scope_user_id(presentation_id)
|
||||
payload = [{"role": "user", "content": self._truncate(message)}]
|
||||
|
||||
def _add():
|
||||
try:
|
||||
return client.add(payload, user_id=scoped_user_id, infer=False)
|
||||
except TypeError:
|
||||
return client.add(
|
||||
messages=payload,
|
||||
user_id=scoped_user_id,
|
||||
infer=False,
|
||||
)
|
||||
|
||||
try:
|
||||
await asyncio.to_thread(_add)
|
||||
except Exception:
|
||||
LOGGER.exception(
|
||||
"Failed to add mem0 memory for presentation_id=%s", presentation_id
|
||||
)
|
||||
|
||||
async def store_generation_context(
|
||||
self,
|
||||
presentation_id: UUID,
|
||||
system_prompt: Optional[str],
|
||||
user_prompt: Optional[str],
|
||||
extracted_document_text: Optional[str],
|
||||
source_content: Optional[str],
|
||||
instructions: Optional[str],
|
||||
):
|
||||
if source_content:
|
||||
await self._add_message(
|
||||
presentation_id,
|
||||
"[presentation_source_prompt]\n" + source_content,
|
||||
)
|
||||
|
||||
if instructions:
|
||||
await self._add_message(
|
||||
presentation_id,
|
||||
"[presentation_generation_instructions]\n" + instructions,
|
||||
)
|
||||
|
||||
if system_prompt:
|
||||
await self._add_message(
|
||||
presentation_id,
|
||||
"[outline_system_prompt]\n" + system_prompt,
|
||||
)
|
||||
|
||||
if user_prompt:
|
||||
await self._add_message(
|
||||
presentation_id,
|
||||
"[outline_user_prompt]\n" + user_prompt,
|
||||
)
|
||||
|
||||
if extracted_document_text:
|
||||
await self._add_message(
|
||||
presentation_id,
|
||||
"[document_extracted_text]\n" + extracted_document_text,
|
||||
)
|
||||
|
||||
async def store_generated_outlines(self, presentation_id: UUID, outlines: Any):
|
||||
if outlines is None:
|
||||
return
|
||||
|
||||
try:
|
||||
outlines_text = (
|
||||
outlines
|
||||
if isinstance(outlines, str)
|
||||
else json.dumps(outlines, ensure_ascii=False)
|
||||
)
|
||||
except Exception:
|
||||
outlines_text = str(outlines)
|
||||
|
||||
await self._add_message(
|
||||
presentation_id,
|
||||
"[generated_outlines]\n" + outlines_text,
|
||||
)
|
||||
|
||||
async def store_slide_edit(
|
||||
self,
|
||||
presentation_id: UUID,
|
||||
slide_index: Optional[int],
|
||||
edit_prompt: str,
|
||||
edited_slide_content: Any,
|
||||
):
|
||||
try:
|
||||
edited_text = (
|
||||
edited_slide_content
|
||||
if isinstance(edited_slide_content, str)
|
||||
else json.dumps(edited_slide_content, ensure_ascii=False)
|
||||
)
|
||||
except Exception:
|
||||
edited_text = str(edited_slide_content)
|
||||
|
||||
index_text = f"{slide_index}" if slide_index is not None else "unknown"
|
||||
message = (
|
||||
f"[slide_edit]\n"
|
||||
f"slide_index={index_text}\n"
|
||||
f"user_edit_prompt={edit_prompt}\n"
|
||||
f"edited_slide_content={edited_text}"
|
||||
)
|
||||
await self._add_message(presentation_id, message)
|
||||
|
||||
async def retrieve_context(self, presentation_id: UUID, query: str) -> str:
|
||||
client = await self._get_client()
|
||||
if client is None:
|
||||
return ""
|
||||
|
||||
scoped_user_id = self._scope_user_id(presentation_id)
|
||||
|
||||
def _search():
|
||||
try:
|
||||
return client.search(
|
||||
query,
|
||||
filters={"user_id": scoped_user_id},
|
||||
top_k=self._top_k,
|
||||
)
|
||||
except TypeError:
|
||||
return client.search(
|
||||
query,
|
||||
user_id=scoped_user_id,
|
||||
top_k=self._top_k,
|
||||
)
|
||||
|
||||
try:
|
||||
response = await asyncio.to_thread(_search)
|
||||
except Exception:
|
||||
LOGGER.exception(
|
||||
"Failed to search mem0 context for presentation_id=%s", presentation_id
|
||||
)
|
||||
return ""
|
||||
|
||||
results = []
|
||||
if isinstance(response, dict):
|
||||
results = response.get("results") or []
|
||||
elif isinstance(response, list):
|
||||
results = response
|
||||
|
||||
memories: list[str] = []
|
||||
for item in results:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
memory_text = item.get("memory") or item.get("text") or item.get("data")
|
||||
if not memory_text:
|
||||
continue
|
||||
normalized = str(memory_text).strip()
|
||||
if normalized:
|
||||
memories.append(normalized)
|
||||
|
||||
if not memories:
|
||||
return ""
|
||||
|
||||
deduped_memories = list(dict.fromkeys(memories))
|
||||
context = "\n\n".join(deduped_memories)
|
||||
return self._truncate(context, self._max_context_chars)
|
||||
|
||||
|
||||
MEM0_PRESENTATION_MEMORY_SERVICE = Mem0PresentationMemoryService()
|
||||
81
servers/fastapi/tests/test_liteparse_service.py
Normal file
81
servers/fastapi/tests/test_liteparse_service.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
from services.liteparse_service import LiteParseService
|
||||
|
||||
|
||||
def _ok_process(stdout: str = '{"ok": true, "text": "ok"}'):
|
||||
return SimpleNamespace(returncode=0, stdout=stdout, stderr="")
|
||||
|
||||
|
||||
class TestLiteParseService:
|
||||
def test_parse_uses_safe_defaults(self):
|
||||
with patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
"LITEPARSE_DPI": "",
|
||||
"LITEPARSE_NUM_WORKERS": "",
|
||||
},
|
||||
clear=False,
|
||||
), patch.object(
|
||||
LiteParseService,
|
||||
"check_runtime_ready",
|
||||
return_value=(True, "ok"),
|
||||
), patch(
|
||||
"services.liteparse_service.subprocess.run",
|
||||
return_value=_ok_process(),
|
||||
) as mock_run:
|
||||
service = LiteParseService(timeout_seconds=30)
|
||||
service.parse("/tmp/sample.pdf", ocr_enabled=True, ocr_language="eng")
|
||||
|
||||
command = mock_run.call_args.args[0]
|
||||
assert "--dpi" in command
|
||||
assert command[command.index("--dpi") + 1] == "120"
|
||||
assert "--num-workers" in command
|
||||
assert command[command.index("--num-workers") + 1] == "1"
|
||||
|
||||
def test_parse_uses_env_overrides(self):
|
||||
with patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
"LITEPARSE_DPI": "96",
|
||||
"LITEPARSE_NUM_WORKERS": "2",
|
||||
},
|
||||
clear=False,
|
||||
), patch.object(
|
||||
LiteParseService,
|
||||
"check_runtime_ready",
|
||||
return_value=(True, "ok"),
|
||||
), patch(
|
||||
"services.liteparse_service.subprocess.run",
|
||||
return_value=_ok_process(),
|
||||
) as mock_run:
|
||||
service = LiteParseService(timeout_seconds=30)
|
||||
service.parse("/tmp/sample.pdf", ocr_enabled=True, ocr_language="eng")
|
||||
|
||||
command = mock_run.call_args.args[0]
|
||||
assert command[command.index("--dpi") + 1] == "96"
|
||||
assert command[command.index("--num-workers") + 1] == "2"
|
||||
|
||||
def test_parse_clamps_invalid_env_values(self):
|
||||
with patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
"LITEPARSE_DPI": "-1",
|
||||
"LITEPARSE_NUM_WORKERS": "0",
|
||||
},
|
||||
clear=False,
|
||||
), patch.object(
|
||||
LiteParseService,
|
||||
"check_runtime_ready",
|
||||
return_value=(True, "ok"),
|
||||
), patch(
|
||||
"services.liteparse_service.subprocess.run",
|
||||
return_value=_ok_process(),
|
||||
) as mock_run:
|
||||
service = LiteParseService(timeout_seconds=30)
|
||||
service.parse("/tmp/sample.pdf", ocr_enabled=True, ocr_language="eng")
|
||||
|
||||
command = mock_run.call_args.args[0]
|
||||
assert command[command.index("--dpi") + 1] == "72"
|
||||
assert command[command.index("--num-workers") + 1] == "1"
|
||||
156
servers/fastapi/tests/test_mem0_presentation_memory_service.py
Normal file
156
servers/fastapi/tests/test_mem0_presentation_memory_service.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
import asyncio
|
||||
import uuid
|
||||
from unittest.mock import patch
|
||||
|
||||
from services.mem0_presentation_memory_service import Mem0PresentationMemoryService
|
||||
|
||||
|
||||
class FakeMemoryClient:
|
||||
instances = []
|
||||
|
||||
def __init__(self, config=None):
|
||||
self.config = config
|
||||
self.add_calls = []
|
||||
self.search_calls = []
|
||||
self.next_search_response = {"results": []}
|
||||
FakeMemoryClient.instances.append(self)
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, config):
|
||||
return cls(config=config)
|
||||
|
||||
def add(self, *args, **kwargs):
|
||||
messages = kwargs.get("messages") if "messages" in kwargs else None
|
||||
if messages is None and args:
|
||||
messages = args[0]
|
||||
|
||||
self.add_calls.append(
|
||||
{
|
||||
"messages": messages,
|
||||
"user_id": kwargs.get("user_id"),
|
||||
"infer": kwargs.get("infer"),
|
||||
}
|
||||
)
|
||||
return {"ok": True}
|
||||
|
||||
def search(self, query, *args, **kwargs):
|
||||
self.search_calls.append(
|
||||
{
|
||||
"query": query,
|
||||
"filters": kwargs.get("filters"),
|
||||
"user_id": kwargs.get("user_id"),
|
||||
"top_k": kwargs.get("top_k"),
|
||||
}
|
||||
)
|
||||
return self.next_search_response
|
||||
|
||||
|
||||
class FakeMem0Module:
|
||||
Memory = FakeMemoryClient
|
||||
|
||||
|
||||
class TestMem0PresentationMemoryService:
|
||||
def setup_method(self):
|
||||
FakeMemoryClient.instances = []
|
||||
|
||||
def test_store_generation_context_uses_presentation_scope(self):
|
||||
with patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
"MEM0_ENABLED": "true",
|
||||
"APP_DATA_DIRECTORY": "/tmp/presenton-test",
|
||||
},
|
||||
clear=False,
|
||||
), patch(
|
||||
"services.mem0_presentation_memory_service.import_module",
|
||||
return_value=FakeMem0Module,
|
||||
):
|
||||
service = Mem0PresentationMemoryService()
|
||||
presentation_id = uuid.uuid4()
|
||||
asyncio.run(
|
||||
service.store_generation_context(
|
||||
presentation_id=presentation_id,
|
||||
system_prompt="system prompt",
|
||||
user_prompt="user prompt",
|
||||
extracted_document_text="doc text",
|
||||
source_content="seed prompt",
|
||||
instructions="be concise",
|
||||
)
|
||||
)
|
||||
|
||||
assert len(FakeMemoryClient.instances) == 1
|
||||
client = FakeMemoryClient.instances[0]
|
||||
assert client.config is not None
|
||||
assert client.config["vector_store"]["provider"] == "qdrant"
|
||||
assert client.config["embedder"]["provider"] == "fastembed"
|
||||
assert (
|
||||
client.config["embedder"]["config"]["model"]
|
||||
== "BAAI/bge-small-en-v1.5"
|
||||
)
|
||||
assert client.config["embedder"]["config"]["embedding_dims"] == 384
|
||||
assert client.config["vector_store"]["config"]["on_disk"] is True
|
||||
assert client.config["vector_store"]["config"]["embedding_model_dims"] == 384
|
||||
assert len(client.add_calls) == 5
|
||||
|
||||
scoped_user_id = f"presentation:{presentation_id}"
|
||||
for call in client.add_calls:
|
||||
assert call["user_id"] == scoped_user_id
|
||||
assert call["infer"] is False
|
||||
|
||||
serialized_messages = "\n".join(
|
||||
str(call["messages"][0]["content"]) for call in client.add_calls
|
||||
)
|
||||
assert "[outline_system_prompt]" in serialized_messages
|
||||
assert "[outline_user_prompt]" in serialized_messages
|
||||
assert "[document_extracted_text]" in serialized_messages
|
||||
assert "[presentation_source_prompt]" in serialized_messages
|
||||
|
||||
def test_retrieve_context_uses_same_scope_and_deduplicates(self):
|
||||
with patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
"MEM0_ENABLED": "true",
|
||||
"MEM0_TOP_K": "5",
|
||||
"APP_DATA_DIRECTORY": "/tmp/presenton-test",
|
||||
},
|
||||
clear=False,
|
||||
), patch(
|
||||
"services.mem0_presentation_memory_service.import_module",
|
||||
return_value=FakeMem0Module,
|
||||
):
|
||||
service = Mem0PresentationMemoryService()
|
||||
presentation_id = uuid.uuid4()
|
||||
|
||||
asyncio.run(
|
||||
service.store_generated_outlines(
|
||||
presentation_id,
|
||||
{"slides": [{"content": "One"}]},
|
||||
)
|
||||
)
|
||||
|
||||
client = FakeMemoryClient.instances[0]
|
||||
client.next_search_response = {
|
||||
"results": [
|
||||
{"memory": "Memory A"},
|
||||
{"memory": "Memory A"},
|
||||
{"memory": "Memory B"},
|
||||
]
|
||||
}
|
||||
|
||||
context = asyncio.run(
|
||||
service.retrieve_context(
|
||||
presentation_id=presentation_id,
|
||||
query="change the conclusion",
|
||||
)
|
||||
)
|
||||
|
||||
assert "Memory A" in context
|
||||
assert "Memory B" in context
|
||||
assert context.count("Memory A") == 1
|
||||
|
||||
assert len(client.search_calls) == 1
|
||||
assert client.search_calls[0]["query"] == "change the conclusion"
|
||||
assert client.search_calls[0]["filters"] == {
|
||||
"user_id": f"presentation:{presentation_id}"
|
||||
}
|
||||
assert client.search_calls[0]["top_k"] == 5
|
||||
|
|
@ -24,7 +24,17 @@ def get_system_prompt(
|
|||
tone: Optional[str] = None,
|
||||
verbosity: Optional[str] = None,
|
||||
instructions: Optional[str] = None,
|
||||
memory_context: Optional[str] = None,
|
||||
):
|
||||
memory_block = (
|
||||
"\n # Retrieved Presentation Memory Context\n"
|
||||
f" {memory_context}\n"
|
||||
" - Use this context only if it is relevant to the user prompt.\n"
|
||||
" - Prefer this context over assumptions when resolving ambiguity.\n"
|
||||
if memory_context
|
||||
else ""
|
||||
)
|
||||
|
||||
return f"""
|
||||
Edit Slide data and speaker note based on provided prompt, follow mentioned steps and notes and provide structured output.
|
||||
|
||||
|
|
@ -45,6 +55,7 @@ def get_system_prompt(
|
|||
- Make sure to follow language guidelines.
|
||||
- Speaker note should be normal text, not markdown.
|
||||
- Speaker note should be simple, clear, concise and to the point.
|
||||
{memory_block}
|
||||
|
||||
**Go through all notes and steps and make sure they are followed, including mentioned constraints**
|
||||
"""
|
||||
|
|
@ -77,10 +88,11 @@ def get_messages(
|
|||
tone: Optional[str] = None,
|
||||
verbosity: Optional[str] = None,
|
||||
instructions: Optional[str] = None,
|
||||
memory_context: Optional[str] = None,
|
||||
):
|
||||
return [
|
||||
LLMSystemMessage(
|
||||
content=get_system_prompt(tone, verbosity, instructions),
|
||||
content=get_system_prompt(tone, verbosity, instructions, memory_context),
|
||||
),
|
||||
LLMUserMessage(
|
||||
content=get_user_prompt(prompt, slide_data, language),
|
||||
|
|
@ -96,6 +108,7 @@ async def get_edited_slide_content(
|
|||
tone: Optional[str] = None,
|
||||
verbosity: Optional[str] = None,
|
||||
instructions: Optional[str] = None,
|
||||
memory_context: Optional[str] = None,
|
||||
):
|
||||
model = get_model()
|
||||
|
||||
|
|
@ -120,7 +133,13 @@ async def get_edited_slide_content(
|
|||
response = await client.generate_structured(
|
||||
model=model,
|
||||
messages=get_messages(
|
||||
prompt, slide.content, language, tone, verbosity, instructions
|
||||
prompt,
|
||||
slide.content,
|
||||
language,
|
||||
tone,
|
||||
verbosity,
|
||||
instructions,
|
||||
memory_context,
|
||||
),
|
||||
response_format=response_schema,
|
||||
strict=False,
|
||||
|
|
|
|||
|
|
@ -32,11 +32,18 @@ system_prompt = """
|
|||
"""
|
||||
|
||||
|
||||
def get_user_prompt(prompt: str, html: str):
|
||||
def get_user_prompt(prompt: str, html: str, memory_context: Optional[str] = None):
|
||||
memory_block = (
|
||||
f"\n **Retrieved Presentation Memory Context:**\n {memory_context}\n"
|
||||
if memory_context
|
||||
else ""
|
||||
)
|
||||
|
||||
return f"""
|
||||
Please edit the following slide HTML based on this prompt:
|
||||
|
||||
**Edit Request:** {prompt}
|
||||
{memory_block}
|
||||
|
||||
**Current HTML:**
|
||||
```html
|
||||
|
|
@ -47,7 +54,9 @@ def get_user_prompt(prompt: str, html: str):
|
|||
"""
|
||||
|
||||
|
||||
async def get_edited_slide_html(prompt: str, html: str):
|
||||
async def get_edited_slide_html(
|
||||
prompt: str, html: str, memory_context: Optional[str] = None
|
||||
):
|
||||
model = get_model()
|
||||
|
||||
client = LLMClient()
|
||||
|
|
@ -56,7 +65,9 @@ async def get_edited_slide_html(prompt: str, html: str):
|
|||
model=model,
|
||||
messages=[
|
||||
LLMSystemMessage(content=system_prompt),
|
||||
LLMUserMessage(content=get_user_prompt(prompt, html)),
|
||||
LLMUserMessage(
|
||||
content=get_user_prompt(prompt, html, memory_context)
|
||||
),
|
||||
],
|
||||
)
|
||||
return extract_html_from_response(response) or html
|
||||
|
|
|
|||
|
|
@ -12,12 +12,20 @@ def get_messages(
|
|||
slide_data: dict,
|
||||
layout: PresentationLayoutModel,
|
||||
current_slide_layout: int,
|
||||
memory_context: str = "",
|
||||
):
|
||||
memory_block = (
|
||||
f"\n # Retrieved Presentation Memory Context\n {memory_context}\n"
|
||||
if memory_context
|
||||
else ""
|
||||
)
|
||||
|
||||
return [
|
||||
LLMSystemMessage(
|
||||
content=f"""
|
||||
Select a Slide Layout index based on provided user prompt and current slide data.
|
||||
{layout.to_string()}
|
||||
{memory_block}
|
||||
|
||||
# Notes
|
||||
- Do not select different slide layout than current unless absolutely necessary as per user prompt.
|
||||
|
|
@ -40,6 +48,7 @@ async def get_slide_layout_from_prompt(
|
|||
prompt: str,
|
||||
layout: PresentationLayoutModel,
|
||||
slide: SlideModel,
|
||||
memory_context: str = "",
|
||||
) -> SlideLayoutModel:
|
||||
|
||||
client = LLMClient()
|
||||
|
|
@ -55,6 +64,7 @@ async def get_slide_layout_from_prompt(
|
|||
slide.content,
|
||||
layout,
|
||||
slide_layout_index,
|
||||
memory_context,
|
||||
),
|
||||
response_format=SlideLayoutIndex.model_json_schema(),
|
||||
strict=True,
|
||||
|
|
|
|||
373
servers/fastapi/uv.lock
generated
373
servers/fastapi/uv.lock
generated
|
|
@ -237,6 +237,24 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/63/13/47bba97924ebe86a62ef83dc75b7c8a881d53c535f83e2c54c4bd701e05c/bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57967b7a28d855313a963aaea51bf6df89f833db4320da458e5b3c5ab6d4c938", size = 280110, upload-time = "2025-02-28T01:24:05.896Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blis"
|
||||
version = "1.3.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "numpy" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d0/d0/d8cc8c9a4488a787e7fa430f6055e5bd1ddb22c340a751d9e901b82e2efe/blis-1.3.3.tar.gz", hash = "sha256:034d4560ff3cc43e8aa37e188451b0440e3261d989bb8a42ceee865607715ecd", size = 2644873, upload-time = "2025-11-17T12:28:30.511Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/0a/a4c8736bc497d386b0ffc76d321f478c03f1a4725e52092f93b38beb3786/blis-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e10c8d3e892b1dbdff365b9d00e08291876fc336915bf1a5e9f188ed087e1a91", size = 6925522, upload-time = "2025-11-17T12:27:29.199Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/5a/3437009282f23684ecd3963a8b034f9307cdd2bf4484972e5a6b096bf9ac/blis-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66e6249564f1db22e8af1e0513ff64134041fa7e03c8dd73df74db3f4d8415a7", size = 1232787, upload-time = "2025-11-17T12:27:30.996Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/0e/82221910d16259ce3017c1442c468a3f206a4143a96fbba9f5b5b81d62e8/blis-1.3.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7260da065958b4e5475f62f44895ef9d673b0f47dcf61b672b22b7dae1a18505", size = 2844596, upload-time = "2025-11-17T12:27:32.601Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/93/ab547f1a5c23e20bca16fbcf04021c32aac3f969be737ea4980509a7ca90/blis-1.3.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e9327a6ca67de8ae76fe071e8584cc7f3b2e8bfadece4961d40f2826e1cda2df", size = 11377746, upload-time = "2025-11-17T12:27:35.342Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/a6/7733820aa62da32526287a63cd85c103b2b323b186c8ee43b7772ff7017c/blis-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c4ae70629cf302035d268858a10ca4eb6242a01b2dc8d64422f8e6dcb8a8ee74", size = 3041954, upload-time = "2025-11-17T12:27:37.479Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/53/e39d67fd3296b649772780ca6aab081412838ecb54e0b0c6432d01626a50/blis-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45866a9027d43b93e8b59980a23c5d7358b6536fc04606286e39fdcfce1101c2", size = 14251222, upload-time = "2025-11-17T12:27:39.705Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/44/b749f8777b020b420bceaaf60f66432fc30cc904ca5b69640ec9cbef11ed/blis-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:27f82b8633030f8d095d2b412dffa7eb6dbc8ee43813139909a20012e54422ea", size = 6171233, upload-time = "2025-11-17T12:27:41.921Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "build"
|
||||
version = "1.3.0"
|
||||
|
|
@ -260,6 +278,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "catalogue"
|
||||
version = "2.0.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/38/b4/244d58127e1cdf04cf2dc7d9566f0d24ef01d5ce21811bab088ecc62b5ea/catalogue-2.0.10.tar.gz", hash = "sha256:4f56daa940913d3f09d589c191c74e5a6d51762b3a9e37dd53b7437afd6cda15", size = 19561, upload-time = "2023-09-25T06:29:24.962Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/96/d32b941a501ab566a16358d68b6eb4e4acc373fab3c3c4d7d9e649f7b4bb/catalogue-2.0.10-py3-none-any.whl", hash = "sha256:58c2de0020aa90f4a2da7dfad161bf7b3b054c86a5f09fcedc0b2b740c109a9f", size = 17325, upload-time = "2023-09-25T06:29:23.337Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2025.8.3"
|
||||
|
|
@ -368,6 +395,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudpathlib"
|
||||
version = "0.23.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f4/18/2ac35d6b3015a0c74e923d94fc69baf8307f7c3233de015d69f99e17afa8/cloudpathlib-0.23.0.tar.gz", hash = "sha256:eb38a34c6b8a048ecfd2b2f60917f7cbad4a105b7c979196450c2f541f4d6b4b", size = 53126, upload-time = "2025-10-07T22:47:56.278Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/8a/c4bb04426d608be4a3171efa2e233d2c59a5c8937850c10d098e126df18e/cloudpathlib-0.23.0-py3-none-any.whl", hash = "sha256:8520b3b01468fee77de37ab5d50b1b524ea6b4a8731c35d1b7407ac0cd716002", size = 62755, upload-time = "2025-10-07T22:47:54.905Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
|
|
@ -389,6 +425,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", size = 46018, upload-time = "2021-06-11T10:22:42.561Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "confection"
|
||||
version = "1.3.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ca/65/efd0fe8a936fc8ca2978cb7b82581fb20d901c6039e746a808f746b7647b/confection-1.3.3.tar.gz", hash = "sha256:f0f6810d567ff73993fe74d218ca5e1ffb6a44fb03f391257fc5d033546cbfaa", size = 54895, upload-time = "2026-03-24T18:45:24.331Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/e4/d66708bdf0d92fb4d49b22cdff4b10cec38aca5dcd7e81d909bb55c65cd7/confection-1.3.3-py3-none-any.whl", hash = "sha256:b9fef9ee84b237ef4611ec3eb5797b70e13063e6310ad9f15536373f5e313c82", size = 35902, upload-time = "2026-03-24T18:45:22.664Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "45.0.5"
|
||||
|
|
@ -445,6 +490,22 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/df/e5/a7b6db64f08cfe065e531ec6b508fa7dac704fab70d05adb5bc0c2c1d1b6/cyclopts-3.22.5-py3-none-any.whl", hash = "sha256:92efb4a094d9812718d7efe0bffa319a19cb661f230dbf24406c18cd8809fb82", size = 84994, upload-time = "2025-07-31T18:18:35.939Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cymem"
|
||||
version = "2.0.13"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/2f0fbb32535c3731b7c2974c569fb9325e0a38ed5565a08e1139a3b71e82/cymem-2.0.13.tar.gz", hash = "sha256:1c91a92ae8c7104275ac26bd4d29b08ccd3e7faff5893d3858cb6fadf1bc1588", size = 12320, upload-time = "2025-11-14T14:58:36.902Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/64/1db41f7576a6b69f70367e3c15e968fd775ba7419e12059c9966ceb826f8/cymem-2.0.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:673183466b0ff2e060d97ec5116711d44200b8f7be524323e080d215ee2d44a5", size = 43587, upload-time = "2025-11-14T14:57:22.39Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/13/57f936fc08551323aab3f92ff6b7f4d4b89d5b4e495c870a67cb8d279757/cymem-2.0.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bee2791b3f6fc034ce41268851462bf662ff87e8947e35fb6dd0115b4644a61f", size = 43139, upload-time = "2025-11-14T14:57:23.363Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/a6/9345754be51e0479aa387b7b6cffc289d0fd3201aaeb8dade4623abd1e02/cymem-2.0.13-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f3aee3adf16272bca81c5826eed55ba3c938add6d8c9e273f01c6b829ecfde22", size = 245063, upload-time = "2025-11-14T14:57:24.839Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/01/6bc654101526fa86e82bf6b05d99b2cd47c30a333cfe8622c26c0592beb2/cymem-2.0.13-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:30c4e75a3a1d809e89106b0b21803eb78e839881aa1f5b9bd27b454bc73afde3", size = 244496, upload-time = "2025-11-14T14:57:26.42Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/fb/853b7b021e701a1f41687f3704d5f469aeb2a4f898c3fbb8076806885955/cymem-2.0.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec99efa03cf8ec11c8906aa4d4cc0c47df393bc9095c9dd64b89b9b43e220b04", size = 243287, upload-time = "2025-11-14T14:57:27.542Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/2b/0e4664cafc581de2896d75000651fd2ce7094d33263f466185c28ffc96e4/cymem-2.0.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c90a6ecba994a15b17a3f45d7ec74d34081df2f73bd1b090e2adc0317e4e01b6", size = 248287, upload-time = "2025-11-14T14:57:29.055Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/0f/f94c6950edbfc2aafb81194fc40b6cacc8e994e9359d3cb4328c5705b9b5/cymem-2.0.13-cp311-cp311-win_amd64.whl", hash = "sha256:ce821e6ba59148ed17c4567113b8683a6a0be9c9ac86f14e969919121efb61a5", size = 40116, upload-time = "2025-11-14T14:57:30.592Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/df/2455eff6ac0381ff165db6883b311f7016e222e3dd62185517f8e8187ed0/cymem-2.0.13-cp311-cp311-win_arm64.whl", hash = "sha256:0dca715e708e545fd1d97693542378a00394b20a37779c1ae2c8bdbb43acef79", size = 36349, upload-time = "2025-11-14T14:57:31.573Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirtyjson"
|
||||
version = "1.0.8"
|
||||
|
|
@ -783,6 +844,19 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "4.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "hpack" },
|
||||
{ name = "hyperframe" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hf-xet"
|
||||
version = "1.1.5"
|
||||
|
|
@ -798,6 +872,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/f0/55/ef77a85ee443ae05a9e9cba1c9f0dd9241eb42da2aeba1dc50f51154c81a/hf_xet-1.1.5-cp37-abi3-win_amd64.whl", hash = "sha256:73e167d9807d166596b4b2f0b585c6d5bd84a26dea32843665a8b58f6edba245", size = 2738931, upload-time = "2025-06-20T21:48:39.482Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hpack"
|
||||
version = "4.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.9"
|
||||
|
|
@ -841,6 +924,11 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
http2 = [
|
||||
{ name = "h2" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx-sse"
|
||||
version = "0.4.1"
|
||||
|
|
@ -881,6 +969,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", size = 86794, upload-time = "2021-09-17T21:40:39.897Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyperframe"
|
||||
version = "6.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.10"
|
||||
|
|
@ -1156,6 +1253,29 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mem0ai"
|
||||
version = "2.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "openai" },
|
||||
{ name = "posthog" },
|
||||
{ name = "protobuf" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pytz" },
|
||||
{ name = "qdrant-client" },
|
||||
{ name = "sqlalchemy" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a8/41/4b786308d595ff5dc958b9916c0a5ae19af6337c7c09c4f22075400440d5/mem0ai-2.0.0.tar.gz", hash = "sha256:69a029d6e36d6f9cd30a3f2baab68b8e94e984ee91737ed5b6d78bc61df41cd8", size = 210776, upload-time = "2026-04-16T11:51:02.135Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/83/433c9e433aa8eede63bc1538bf97a43af3b6eb9cd4cd78ae53dcd484b5e4/mem0ai-2.0.0-py3-none-any.whl", hash = "sha256:77b185d9a490358e806497c42164ab2464109ff44fde10e5fc834996b0011649", size = 298513, upload-time = "2026-04-16T11:51:00.233Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
nlp = [
|
||||
{ name = "spacy" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mmh3"
|
||||
version = "5.2.0"
|
||||
|
|
@ -1225,6 +1345,22 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/d8/30/9aec301e9772b098c1f5c0ca0279237c9766d94b97802e9888010c64b0ed/multidict-6.6.3-py3-none-any.whl", hash = "sha256:8db10f29c7541fc5da4defd8cd697e1ca429db743fa716325f236079b96f775a", size = 12313, upload-time = "2025-06-30T15:53:45.437Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "murmurhash"
|
||||
version = "1.0.15"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/23/2e/88c147931ea9725d634840d538622e94122bceaf346233349b7b5c62964b/murmurhash-1.0.15.tar.gz", hash = "sha256:58e2b27b7847f9e2a6edf10b47a8c8dd70a4705f45dccb7bf76aeadacf56ba01", size = 13291, upload-time = "2025-11-14T09:51:15.272Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/ca/77d3e69924a8eb4508bb4f0ad34e46adbeedeb93616a71080e61e53dad71/murmurhash-1.0.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f32307fb9347680bb4fe1cbef6362fb39bd994f1b59abd8c09ca174e44199081", size = 27397, upload-time = "2025-11-14T09:50:03.077Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/53/a936f577d35b245d47b310f29e5e9f09fcac776c8c992f1ab51a9fb0cee2/murmurhash-1.0.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:539d8405885d1d19c005f3a2313b47e8e54b0ee89915eb8dfbb430b194328e6c", size = 27692, upload-time = "2025-11-14T09:50:04.144Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/64/5f8cfd1fd9cbeb43fcff96672f5bd9e7e1598d1c970f808ecd915490dc20/murmurhash-1.0.15-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c4cd739a00f5a4602201b74568ddabae46ec304719d9be752fd8f534a9464b5e", size = 128396, upload-time = "2025-11-14T09:50:05.268Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/10/d9ce29d559a75db0d8a3f13ea12c7f541ec9de2afca38dc70418b890eedb/murmurhash-1.0.15-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44d211bcc3ec203c47dac06f48ee871093fcbdffa6652a6cc5ea7180306680a8", size = 128687, upload-time = "2025-11-14T09:50:06.527Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/cd/dc97ab7e68cdfa1537a56e36dbc846c5a66701cc39ecee2d4399fe61996c/murmurhash-1.0.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f9bf47101354fb1dc4b2e313192566f04ba295c28a37e2f71c692759acc1ba3c", size = 128198, upload-time = "2025-11-14T09:50:08.062Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/73/32f2aaa22c1e4afae337106baf0c938abf36a6cc879cfee83a00461bbbf7/murmurhash-1.0.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c69b4d3bcd6233782a78907fe10b9b7a796bdc5d28060cf097d067bec280a5d", size = 127214, upload-time = "2025-11-14T09:50:09.265Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/ed/812103a7f353eba2d83655b08205e13a38c93b4db0692f94756e1eb44516/murmurhash-1.0.15-cp311-cp311-win_amd64.whl", hash = "sha256:e43a69496342ce530bdd670264cb7c8f45490b296e4764c837ce577e3c7ebd53", size = 25241, upload-time = "2025-11-14T09:50:10.373Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/5f/2c511bdd28f7c24da37a00116ffd0432b65669d098f0d0260c66ac0ffdc2/murmurhash-1.0.15-cp311-cp311-win_arm64.whl", hash = "sha256:f3e99a6ee36ef5372df5f138e3d9c801420776d3641a34a49e5c2555f44edba7", size = 23216, upload-time = "2025-11-14T09:50:11.651Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nltk"
|
||||
version = "3.9.1"
|
||||
|
|
@ -1586,6 +1722,18 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portalocker"
|
||||
version = "3.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5e/77/65b857a69ed876e1951e88aaba60f5ce6120c33703f7cb61a3c894b8c1b6/portalocker-3.2.0.tar.gz", hash = "sha256:1f3002956a54a8c3730586c5c77bf18fae4149e07eaf1c29fc3faf4d5a3f89ac", size = 95644, upload-time = "2025-06-14T13:20:40.03Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/a6/38c8e2f318bf67d338f4d629e93b0b4b9af331f455f0390ea8ce4a099b26/portalocker-3.2.0-py3-none-any.whl", hash = "sha256:3cdc5f565312224bc570c49337bd21428bba0ef363bbcf58b9ef4a9f11779968", size = 22424, upload-time = "2025-06-14T13:20:38.083Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "posthog"
|
||||
version = "5.4.0"
|
||||
|
|
@ -1619,6 +1767,7 @@ dependencies = [
|
|||
{ name = "fastembed-vectorstore" },
|
||||
{ name = "fastmcp" },
|
||||
{ name = "google-genai" },
|
||||
{ name = "mem0ai", extra = ["nlp"] },
|
||||
{ name = "nltk" },
|
||||
{ name = "openai" },
|
||||
{ name = "pathvalidate" },
|
||||
|
|
@ -1643,6 +1792,7 @@ requires-dist = [
|
|||
{ name = "fastembed-vectorstore", specifier = ">=0.5.2" },
|
||||
{ name = "fastmcp", specifier = ">=2.11.0" },
|
||||
{ name = "google-genai", specifier = ">=1.28.0" },
|
||||
{ name = "mem0ai", extras = ["nlp"], specifier = ">=0.1.115" },
|
||||
{ name = "nltk", specifier = ">=3.9.1" },
|
||||
{ name = "openai", specifier = ">=1.98.0" },
|
||||
{ name = "pathvalidate", specifier = ">=3.3.1" },
|
||||
|
|
@ -1653,6 +1803,26 @@ requires-dist = [
|
|||
{ name = "sqlmodel", specifier = ">=0.0.24" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "preshed"
|
||||
version = "3.0.13"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cymem" },
|
||||
{ name = "murmurhash" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/43/75/fe6b7bbd0dea530a001b0e24c331b21a0be2786e402abf3c57f5dce43d4b/preshed-3.0.13.tar.gz", hash = "sha256:d75f718bbfd97e992f7827e0fa7faf6a91bdd9c922d5baa4b50d62731396cb89", size = 18338, upload-time = "2026-03-23T08:57:31.378Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/d1/7bc39738388b38ff48cecbb326a9b2bb3f422bb32097be92e010f3162395/preshed-3.0.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5268c0e6fa96f50cdf87f516c2d4b32563c12706ee768e75c00e8d0098acd545", size = 136718, upload-time = "2026-03-23T08:56:23.889Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/65/de465b6801740140c2b5d2db6c312ca7937dcfd0442f1ae7d50dee529544/preshed-3.0.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:df642547a1a94079978a0ea8f4593ab4b8d3bd43f767bef0ef64d9a214f8c4c9", size = 137261, upload-time = "2026-03-23T08:56:25.303Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/83/478ee078746a4a413c841542caebd2ea74b659475b8bf5f2e3724b6fe655/preshed-3.0.13-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09397592d333a77f88454e72b7f1f941b2afaf040b392b9e74898dbc4648cdf5", size = 821010, upload-time = "2026-03-23T08:56:26.455Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/2e/1ac761e973966893cd3a0ad3256360365276e2d1e779e351448981a1156a/preshed-3.0.13-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f8e6fe0620ed0f96a246d46447055c447e071cd8222731a045c235e8a758c918", size = 823096, upload-time = "2026-03-23T08:56:28.126Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/51/7824cfd85dd7fe547888de20228ebd87d9acd3708206d30b82211e382d23/preshed-3.0.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:502f93f49a22788203f02d3067d4ea077a0cca3864de6a792eae12e7ce589e14", size = 1812148, upload-time = "2026-03-23T08:56:29.755Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/48/32160a24705d56179de6af838c10a0c735c955dae5f9e4bb344750b79bc2/preshed-3.0.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:acd4d89abeca3678c5d8c89b3cd351314465bc67c7fa053d2644f8513e543386", size = 1881154, upload-time = "2026-03-23T08:56:31.49Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/22/0344b50f8b1ad9e3aac08099c47e1aba91c81602fd117d2673f6606ecae6/preshed-3.0.13-cp311-cp311-win_amd64.whl", hash = "sha256:de87fbabb0f37c3c92d4dd9b94fc82ab73cdab4247cdfbd57ab3926caa983919", size = 122219, upload-time = "2026-03-23T08:56:32.74Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/c4/812eeaa568510f396e27edab01100ca71418f032fd7098b107f12e572361/preshed-3.0.13-cp311-cp311-win_arm64.whl", hash = "sha256:5e2753779832e411e93eb727f3d409c0a6b7408e5ce4dd868076d8ece48c7693", size = 109308, upload-time = "2026-03-23T08:56:33.839Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "propcache"
|
||||
version = "0.3.2"
|
||||
|
|
@ -1975,6 +2145,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/d9/4f/00be2196329ebbff56ce564aa94efb0fbc828d00de250b1980de1a34ab49/python_pptx-1.0.2-py3-none-any.whl", hash = "sha256:160838e0b8565a8b1f67947675886e9fea18aa5e795db7ae531606d68e785cba", size = 472788, upload-time = "2024-08-07T17:33:28.192Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2026.1.post1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pywin32"
|
||||
version = "311"
|
||||
|
|
@ -2002,6 +2181,24 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qdrant-client"
|
||||
version = "1.17.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "grpcio" },
|
||||
{ name = "httpx", extra = ["http2"] },
|
||||
{ name = "numpy" },
|
||||
{ name = "portalocker" },
|
||||
{ name = "protobuf" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "urllib3" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/30/dd/f8a8261b83946af3cd65943c93c4f83e044f01184e8525404989d22a81a5/qdrant_client-1.17.1.tar.gz", hash = "sha256:22f990bbd63485ed97ba551a4c498181fcb723f71dcab5d6e4e43fe1050a2bc0", size = 344979, upload-time = "2026-03-13T17:13:44.678Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/68/69/77d1a971c4b933e8c79403e99bcbb790463da5e48333cc4fd5d412c63c98/qdrant_client-1.17.1-py3-none-any.whl", hash = "sha256:6cda4064adfeaf211c751f3fbc00edbbdb499850918c7aff4855a9a759d56cbd", size = 389947, upload-time = "2026-03-13T17:13:43.156Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "6.2.0"
|
||||
|
|
@ -2220,6 +2417,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/2d/3e/bb34de65a5787f76848a533afbb6610e01fbcdd59e76d8679c254e02255c/sentry_sdk-2.34.1-py2.py3-none-any.whl", hash = "sha256:b7a072e1cdc5abc48101d5146e1ae680fa81fe886d8d95aaa25a0b450c818d32", size = 357743, upload-time = "2025-07-30T11:13:36.145Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "82.0.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.5.4"
|
||||
|
|
@ -2238,6 +2444,18 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smart-open"
|
||||
version = "7.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "wrapt" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/14/33/7a00ac9b4a63afb4279b99a766f6cbe56c443526dcbf5db97b219e21fde9/smart_open-7.6.0.tar.gz", hash = "sha256:44717f46b5ff276fac03b88e5d13d1c416f064f3b7b081381b0fa8889004bd7e", size = 54548, upload-time = "2026-04-13T09:48:04.347Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/de/bc/2761410d0541e975f384bc89f062d716bf119499dd097eb1af33dcd3b1c0/smart_open-7.6.0-py3-none-any.whl", hash = "sha256:2a78f454610a826aa688065b54b4a0a9b12a5599fa61d5190e9bac2df5e5f53f", size = 64591, upload-time = "2026-04-13T09:48:02.687Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
|
|
@ -2247,6 +2465,60 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spacy"
|
||||
version = "3.8.14"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "catalogue" },
|
||||
{ name = "confection" },
|
||||
{ name = "cymem" },
|
||||
{ name = "jinja2" },
|
||||
{ name = "murmurhash" },
|
||||
{ name = "numpy" },
|
||||
{ name = "packaging" },
|
||||
{ name = "preshed" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "requests" },
|
||||
{ name = "setuptools" },
|
||||
{ name = "spacy-legacy" },
|
||||
{ name = "spacy-loggers" },
|
||||
{ name = "srsly" },
|
||||
{ name = "thinc" },
|
||||
{ name = "tqdm" },
|
||||
{ name = "typer" },
|
||||
{ name = "wasabi" },
|
||||
{ name = "weasel" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/8c/0ccf32d9a6b4fd8737bba33d599ddb98934399c1d523f825a4beb4bd1495/spacy-3.8.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c55cb123c3edfba8c252ce6ae27ffb3d7f60a53ba5e108c3534421586c5fdda", size = 6617470, upload-time = "2026-03-29T10:40:25.572Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/61/7f7d38e71daac7f91ffd362fb15645b6f9a68ad231e0ed6ff5c1dc6f6930/spacy-3.8.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab6c1ace316338dac334fc93c849994bbd717f9ebf59d2bc4158e978b2f542ee", size = 6441524, upload-time = "2026-03-29T10:40:27.648Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/ef/18385aa5aeb9bcb299e8074da162b24e5c8bea5aa4d1dfa3dbafb35e9d1f/spacy-3.8.14-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7bece0450cd8ab841cfa8527fcc0ce18c4454f28e3b9fca42a450803a067355b", size = 32050591, upload-time = "2026-03-29T10:40:29.704Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/67/5c4a65ed2cedc598ad000a2b9f45afc76bb8d17a592cc01082dffa8bbc50/spacy-3.8.14-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc5e5f2ed121d57d819d247bb59253dc320a58acbd237b85f86c2aa38cab6bd1", size = 32296467, upload-time = "2026-03-29T10:40:32.557Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/a7/28c118879791b3a7ffa81796d22203daac428e6f75572f1b8da1539e1ac6/spacy-3.8.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c4e5bc5cdefe39ea139985776a2e8eae05e7ff2bf51ca1bd65247dc45feeb8e", size = 32288404, upload-time = "2026-03-29T10:40:35.583Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/1c/32aefcea2468782fcdb994f2f96cac93dc74f6589ce01047db42d9a299a2/spacy-3.8.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2c228f4c9ae618173334c17adb748d66b574b6594bc3575233e15cd5ad1cb26b", size = 33113476, upload-time = "2026-03-29T10:40:38.577Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/32/fc00532eabeace451175dd9b152ddd636e8f6a42248b5d90141f98be2af5/spacy-3.8.14-cp311-cp311-win_amd64.whl", hash = "sha256:6f51d1ce8b1ba30123f6bef6e795c4bc5466608e6e8a015dc828bd21d399aa9c", size = 15359704, upload-time = "2026-03-29T10:40:41.25Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/31/89ff6722ec91f328dc717932849c6f57249c8a9d429d8670a6c8f70e576b/spacy-3.8.14-cp311-cp311-win_arm64.whl", hash = "sha256:c0c6c9d8771cc3708e309b07310d330fc8443a6bca34f4ff20b0f22751d8faf9", size = 14717168, upload-time = "2026-03-29T10:40:43.916Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spacy-legacy"
|
||||
version = "3.0.12"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d9/79/91f9d7cc8db5642acad830dcc4b49ba65a7790152832c4eceb305e46d681/spacy-legacy-3.0.12.tar.gz", hash = "sha256:b37d6e0c9b6e1d7ca1cf5bc7152ab64a4c4671f59c85adaf7a3fcb870357a774", size = 23806, upload-time = "2023-01-23T09:04:15.104Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/55/12e842c70ff8828e34e543a2c7176dac4da006ca6901c9e8b43efab8bc6b/spacy_legacy-3.0.12-py2.py3-none-any.whl", hash = "sha256:476e3bd0d05f8c339ed60f40986c07387c0a71479245d6d0f4298dbd52cda55f", size = 29971, upload-time = "2023-01-23T09:04:13.45Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spacy-loggers"
|
||||
version = "1.0.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/67/3d/926db774c9c98acf66cb4ed7faf6c377746f3e00b84b700d0868b95d0712/spacy-loggers-1.0.5.tar.gz", hash = "sha256:d60b0bdbf915a60e516cc2e653baeff946f0cfc461b452d11a4d5458c6fe5f24", size = 20811, upload-time = "2023-09-11T12:26:52.323Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/33/78/d1a1a026ef3af911159398c939b1509d5c36fe524c7b644f34a5146c4e16/spacy_loggers-1.0.5-py3-none-any.whl", hash = "sha256:196284c9c446cc0cdb944005384270d775fdeaf4f494d8e269466cfa497ef645", size = 22343, upload-time = "2023-09-11T12:26:50.586Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlalchemy"
|
||||
version = "2.0.42"
|
||||
|
|
@ -2281,6 +2553,25 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/16/91/484cd2d05569892b7fef7f5ceab3bc89fb0f8a8c0cde1030d383dbc5449c/sqlmodel-0.0.24-py3-none-any.whl", hash = "sha256:6778852f09370908985b667d6a3ab92910d0d5ec88adcaf23dbc242715ff7193", size = 28622, upload-time = "2025-03-07T05:43:30.37Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "srsly"
|
||||
version = "2.5.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "catalogue" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2b/db/f794f219a6c788b881252d2536a8c4a97d2bdaadc690391e1cb53d123d71/srsly-2.5.3.tar.gz", hash = "sha256:08f98dbecbff3a31466c4ae7c833131f59d3655a0ad8ac749e6e2c149e2b0680", size = 490881, upload-time = "2026-03-23T11:56:59.865Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/36/5d7bb412d52e9cca787f9bfe838b596367189b254e50bf90f234a97184bf/srsly-2.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:785a09216ac31570fb301ddb9f61ee73d1f18f8b9561f712dce0b8ac8628bc88", size = 656760, upload-time = "2026-03-23T11:55:47.155Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/dc/124f008cd2be3e887e972cbdeb17c5aee0f42093eca02c7cfd63bb5daf19/srsly-2.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0017c7d2a0cd9a4f1bdc00d946b45edcf90bb0e271e8f084c1ce542bf6708c32", size = 657503, upload-time = "2026-03-23T11:55:48.681Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/8a/2c97244ebab125d55f1bfb7bb94e9572b3e819410dffd6a040eca1112350/srsly-2.5.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:66ebae2c70305987341519ec1a720072a3cb3e4b1d52ac0e9e841f4d02658d3d", size = 1139161, upload-time = "2026-03-23T11:55:50.179Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/ea/ecd396188f7591d80b89665f7af9e3ae02e42683daef57033ad7993ad3f9/srsly-2.5.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4ca4a068f6e14d84113a02fcb875c6b50a6285a12938c0e7a157eb3a63c50a86", size = 1142438, upload-time = "2026-03-23T11:55:52.607Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/65/143e2e143c53d498ad0956f69d0e09189aa7a6e0ee6017758c285ba1ab2d/srsly-2.5.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e283fa2a8f7350fb9fb70ecdee28d59d39c92f4c7f1cc90a44d6b86db3b3a8b3", size = 1101783, upload-time = "2026-03-23T11:55:53.906Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/86/1392a5593de0cd3d08c2d6c071b877c84358a37f63172c4e9cb71706842d/srsly-2.5.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9ffc97e22730ea97b00f7c303ccc60b1305e786afadb2a4a46578dafa4d29da0", size = 1115876, upload-time = "2026-03-23T11:55:55.624Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/a5/6193aa4c08e488821538fcbce2282449e228fd2183ed67d118bb5ccd8b54/srsly-2.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:f09b551f6c3e334652831ac68c770ee4284741ce0a3895bf1ccf2a1178d66cdd", size = 651733, upload-time = "2026-03-23T11:55:56.964Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/a8/a73181743b6d237026615ca75c3fb3e4780736f1390550a7350d0c7f1149/srsly-2.5.3-cp311-cp311-win_arm64.whl", hash = "sha256:21cf09e417d3e4f3fbf7dd337fd6d948c97abd01896b9b4cb80e81cd9778a73a", size = 639124, upload-time = "2026-03-23T11:55:58.532Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sse-starlette"
|
||||
version = "3.0.2"
|
||||
|
|
@ -2327,6 +2618,36 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165, upload-time = "2024-07-05T07:25:29.591Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thinc"
|
||||
version = "8.3.13"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "blis" },
|
||||
{ name = "catalogue" },
|
||||
{ name = "confection" },
|
||||
{ name = "cymem" },
|
||||
{ name = "murmurhash" },
|
||||
{ name = "numpy" },
|
||||
{ name = "packaging" },
|
||||
{ name = "preshed" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "setuptools" },
|
||||
{ name = "srsly" },
|
||||
{ name = "wasabi" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/13/46/76df95f2c327f9a9cef30c1523bf285627897097163584dcf5f77b2ebce2/thinc-8.3.13.tar.gz", hash = "sha256:68e658549fc1eb3ff92aed5147fcbb9c15d6e9cc0e623b4d0998d16522ffb4f9", size = 194640, upload-time = "2026-03-23T07:22:36.41Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/72/ca06842a007e8c794e8c59462f242cdfd6167d7cc9d0155ad004b194b015/thinc-8.3.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4565102638038a01a2193c7f5d41ccbd6233fbdcb1f1b184322a06add4f51f18", size = 844359, upload-time = "2026-03-23T07:21:43.017Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/44/e6aef092f478d263f72eb3933b55a6f37ba97c6a0ea0a61d13fbf9bf0c19/thinc-8.3.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:859fbd9d9b16af5278da23589b4afbe2ab6b0dd615df4d3229b7c4e67cd3107e", size = 812089, upload-time = "2026-03-23T07:21:44.618Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/8a/9ce0424d456cd3580cc3a855b23a7ff86b81d5299fceb496a2f56f06c1c0/thinc-8.3.13-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a518d5c761a0f2341e530e867de133dc3ed814558365b2a68ec53b89c482a43f", size = 4101388, upload-time = "2026-03-23T07:21:46.135Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/51/ec91c0434bd9a1096ab874bbd6dc110c5089d7fc513137e6af59bd051eec/thinc-8.3.13-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:81337dfbee37f58f36c0c70f9a819dce1b32cdc13d959181e10de079621f6ac6", size = 4131972, upload-time = "2026-03-23T07:21:48.403Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/67/e30dea753c90cff5cb9e5feb34948fdb89a6774b84d849585b49e16a730e/thinc-8.3.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fbc0ee16edd260c6a4a9e365ff36d0a682c9e7ca6d7b985682659ef2e3e73826", size = 5101283, upload-time = "2026-03-23T07:21:49.991Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/e9/b7544eddababa16e548b26a96fff29eeb307ce938df5fa4af9371fe8ed5d/thinc-8.3.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0355c37e40d1a9fc2a1b8e9c2e294d8586f6baa97bcac6b9002f2dddb4b82ae9", size = 5264488, upload-time = "2026-03-23T07:21:51.747Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/a9/49391a40d703efc0f7a451310373261835f71fd3e6e2e8cfc08ee02f78ad/thinc-8.3.13-cp311-cp311-win_amd64.whl", hash = "sha256:0a0fa13dcfe4b319c3a396432c1dbff30d3de37dbbdee559e76600ee2b9486df", size = 1795058, upload-time = "2026-03-23T07:21:53.424Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/31/fd5348d44beda12a3ee415cbba9ed4fd0b17ce65db1d473c38a29a8d6153/thinc-8.3.13-cp311-cp311-win_arm64.whl", hash = "sha256:cd8a2b714c061969eee65802965167a6ada1fe708d82fe176d98dcb95ebe182a", size = 1721215, upload-time = "2026-03-23T07:21:55.027Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokenizers"
|
||||
version = "0.21.4"
|
||||
|
|
@ -2447,6 +2768,18 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasabi"
|
||||
version = "1.1.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ac/f9/054e6e2f1071e963b5e746b48d1e3727470b2a490834d18ad92364929db3/wasabi-1.1.3.tar.gz", hash = "sha256:4bb3008f003809db0c3e28b4daf20906ea871a2bb43f9914197d540f4f2e0878", size = 30391, upload-time = "2024-05-31T16:56:18.99Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/06/7c/34330a89da55610daa5f245ddce5aab81244321101614751e7537f125133/wasabi-1.1.3-py3-none-any.whl", hash = "sha256:f76e16e8f7e79f8c4c8be49b4024ac725713ab10cd7f19350ad18a8e3f71728c", size = 27880, upload-time = "2024-05-31T16:56:16.699Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "watchfiles"
|
||||
version = "1.1.0"
|
||||
|
|
@ -2475,6 +2808,26 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/bd/d3/254cea30f918f489db09d6a8435a7de7047f8cb68584477a515f160541d6/watchfiles-1.1.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:923fec6e5461c42bd7e3fd5ec37492c6f3468be0499bc0707b4bbbc16ac21792", size = 454009, upload-time = "2025-06-15T19:06:52.896Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weasel"
|
||||
version = "1.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cloudpathlib" },
|
||||
{ name = "confection" },
|
||||
{ name = "httpx" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "smart-open" },
|
||||
{ name = "srsly" },
|
||||
{ name = "typer" },
|
||||
{ name = "wasabi" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ce/e5/e272bb9a045105a1fdf4b798d8086f5932a178f4d738f17a74f5c9e0ae9a/weasel-1.0.0.tar.gz", hash = "sha256:7b129b44c90cc543b760532974ca1e4eb30dad2aa2026f57bdce66354ae610fc", size = 38682, upload-time = "2026-03-20T08:10:25.266Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/07/57ebf7a6798b016c064bd0ca81b4c6a99daa4dc377b898bc7b41eb6b5af0/weasel-1.0.0-py3-none-any.whl", hash = "sha256:89518acee027f49d743126c3502d35e6dd14f5768be5c37c9af47c171b6005cc", size = 50713, upload-time = "2026-03-20T08:10:23.637Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "websocket-client"
|
||||
version = "1.8.0"
|
||||
|
|
@ -2525,6 +2878,26 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wrapt"
|
||||
version = "2.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/81/60c4471fce95afa5922ca09b88a25f03c93343f759aae0f31fb4412a85c7/wrapt-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:96159a0ee2b0277d44201c3b5be479a9979cf154e8c82fa5df49586a8e7679bb", size = 60666, upload-time = "2026-03-06T02:52:58.934Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/be/80e80e39e7cb90b006a0eaf11c73ac3a62bbfb3068469aec15cc0bc795de/wrapt-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98ba61833a77b747901e9012072f038795de7fc77849f1faa965464f3f87ff2d", size = 61601, upload-time = "2026-03-06T02:53:00.487Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/be/d7c88cd9293c859fc74b232abdc65a229bb953997995d6912fc85af18323/wrapt-2.1.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:767c0dbbe76cae2a60dd2b235ac0c87c9cccf4898aef8062e57bead46b5f6894", size = 114057, upload-time = "2026-03-06T02:52:44.08Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/25/36c04602831a4d685d45a93b3abea61eca7fe35dab6c842d6f5d570ef94a/wrapt-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c691a6bc752c0cc4711cc0c00896fcd0f116abc253609ef64ef930032821842", size = 116099, upload-time = "2026-03-06T02:54:56.74Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/4e/98a6eb417ef551dc277bec1253d5246b25003cf36fdf3913b65cb7657a56/wrapt-2.1.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f3b7d73012ea75aee5844de58c88f44cf62d0d62711e39da5a82824a7c4626a8", size = 112457, upload-time = "2026-03-06T02:53:52.842Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/a6/a6f7186a5297cad8ec53fd7578533b28f795fdf5372368c74bd7e6e9841c/wrapt-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:577dff354e7acd9d411eaf4bfe76b724c89c89c8fc9b7e127ee28c5f7bcb25b6", size = 115351, upload-time = "2026-03-06T02:53:32.684Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/6f/06e66189e721dbebd5cf20e138acc4d1150288ce118462f2fcbff92d38db/wrapt-2.1.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d7b6fd105f8b24e5bd23ccf41cb1d1099796524bcc6f7fbb8fe576c44befbc9", size = 111748, upload-time = "2026-03-06T02:53:08.455Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/43/4808b86f499a51370fbdbdfa6cb91e9b9169e762716456471b619fca7a70/wrapt-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:866abdbf4612e0b34764922ef8b1c5668867610a718d3053d59e24a5e5fcfc15", size = 113783, upload-time = "2026-03-06T02:53:02.02Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/2c/a3f28b8fa7ac2cefa01cfcaca3471f9b0460608d012b693998cd61ef43df/wrapt-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5a0a0a3a882393095573344075189eb2d566e0fd205a2b6414e9997b1b800a8b", size = 57977, upload-time = "2026-03-06T02:53:27.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/c3/2b1c7bd07a27b1db885a2fab469b707bdd35bddf30a113b4917a7e2139d2/wrapt-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:64a07a71d2730ba56f11d1a4b91f7817dc79bc134c11516b75d1921a7c6fcda1", size = 60336, upload-time = "2026-03-06T02:54:28.104Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/5c/76ece7b401b088daa6503d6264dd80f9a727df3e6042802de9a223084ea2/wrapt-2.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:b89f095fe98bc12107f82a9f7d570dc83a0870291aeb6b1d7a7d35575f55d98a", size = 58756, upload-time = "2026-03-06T02:53:16.319Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xlsxwriter"
|
||||
version = "3.2.5"
|
||||
|
|
|
|||
|
|
@ -52,10 +52,9 @@ const CHATGPT_MODELS: CodexModel[] = [
|
|||
{ id: "gpt-5.4-mini", name: "GPT-5.4-Mini" },
|
||||
{ id: "gpt-5.3-codex", name: "GPT-5.3-Codex" },
|
||||
{ id: "gpt-5.2", name: "GPT-5.2" },
|
||||
{ id: "gpt-5.1-codex-mini", name: "GPT-5.1-Codex-Mini" },
|
||||
];
|
||||
|
||||
const DEFAULT_CODEX_MODEL = "gpt-5.1-codex-mini";
|
||||
const DEFAULT_CODEX_MODEL = "gpt-5.2";
|
||||
|
||||
export default function CodexConfig({
|
||||
codexModel,
|
||||
|
|
|
|||
|
|
@ -39,10 +39,9 @@ export const CHATGPT_MODELS: CodexModel[] = [
|
|||
{ id: "gpt-5.4-mini", name: "GPT-5.4-Mini" },
|
||||
{ id: "gpt-5.3-codex", name: "GPT-5.3-Codex" },
|
||||
{ id: "gpt-5.2", name: "GPT-5.2" },
|
||||
{ id: "gpt-5.1-codex-mini", name: "GPT-5.1-Codex-Mini" },
|
||||
];
|
||||
|
||||
export const DEFAULT_CODEX_MODEL = "gpt-5.1-codex-mini";
|
||||
export const DEFAULT_CODEX_MODEL = "gpt-5.2";
|
||||
|
||||
export default function CodexConfig({
|
||||
codexModel,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue