mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-16 01:35:36 -04:00
feat: allow memory import without session (#493)
This commit is contained in:
+23
-8
@@ -28,6 +28,7 @@ from core.database import SessionLocal
|
|||||||
from src.llm_core import llm_call_async
|
from src.llm_core import llm_call_async
|
||||||
from services.memory.memory_extractor import audit_memories
|
from services.memory.memory_extractor import audit_memories
|
||||||
from src.auth_helpers import get_current_user
|
from src.auth_helpers import get_current_user
|
||||||
|
from src.endpoint_resolver import resolve_endpoint
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -313,16 +314,30 @@ def setup_memory_routes(memory_manager: MemoryManager, session_manager: SessionM
|
|||||||
@router.post("/import")
|
@router.post("/import")
|
||||||
async def import_memories_from_file(
|
async def import_memories_from_file(
|
||||||
request: Request,
|
request: Request,
|
||||||
session: str = Form(...),
|
session: str | None = Form(None),
|
||||||
file: UploadFile = File(...)
|
file: UploadFile = File(...)
|
||||||
):
|
):
|
||||||
"""Extract memory suggestions from an uploaded file (PDF, TXT, MD, etc.)."""
|
"""Extract memory suggestions from an uploaded file (PDF, TXT, MD, etc.)."""
|
||||||
from src.auth_helpers import require_privilege
|
from src.auth_helpers import require_privilege
|
||||||
require_privilege(request, "can_manage_memory")
|
require_privilege(request, "can_manage_memory")
|
||||||
try:
|
|
||||||
sess = session_manager.get_session(session)
|
endpoint_url = None
|
||||||
except KeyError:
|
model = None
|
||||||
raise HTTPException(404, "Session not found — needed for LLM config")
|
headers = {}
|
||||||
|
|
||||||
|
if session:
|
||||||
|
try:
|
||||||
|
sess = session_manager.get_session(session)
|
||||||
|
endpoint_url = sess.endpoint_url
|
||||||
|
model = sess.model
|
||||||
|
headers = sess.headers
|
||||||
|
except KeyError:
|
||||||
|
raise HTTPException(404, "Session not found — needed for LLM config")
|
||||||
|
else:
|
||||||
|
endpoint_url, model, headers = resolve_endpoint("utility", owner=_owner(request))
|
||||||
|
|
||||||
|
if not endpoint_url or not model:
|
||||||
|
raise HTTPException(400, "No LLM model configured. Set a default model in Settings.")
|
||||||
|
|
||||||
# Read file content
|
# Read file content
|
||||||
content = await file.read()
|
content = await file.read()
|
||||||
@@ -404,15 +419,15 @@ def setup_memory_routes(memory_manager: MemoryManager, session_manager: SessionM
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
raw = await llm_call_async(
|
raw = await llm_call_async(
|
||||||
sess.endpoint_url,
|
endpoint_url,
|
||||||
sess.model,
|
model,
|
||||||
[
|
[
|
||||||
{"role": "system", "content": import_prompt},
|
{"role": "system", "content": import_prompt},
|
||||||
{"role": "user", "content": f"Document: {filename}\n\n{text}"},
|
{"role": "user", "content": f"Document: {filename}\n\n{text}"},
|
||||||
],
|
],
|
||||||
temperature=0.2,
|
temperature=0.2,
|
||||||
max_tokens=2000,
|
max_tokens=2000,
|
||||||
headers=sess.headers,
|
headers=headers,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Parse JSON
|
# Parse JSON
|
||||||
|
|||||||
+2
-2
@@ -300,7 +300,7 @@
|
|||||||
<input type="file" id="memory-import-file" accept=".txt,.md,.pdf,.csv,.log,.json,.py,.js,.html" hidden />
|
<input type="file" id="memory-import-file" accept=".txt,.md,.pdf,.csv,.log,.json,.py,.js,.html" hidden />
|
||||||
</div>
|
</div>
|
||||||
<p class="memory-desc doclib-desc" style="margin:4px 0 6px;">
|
<p class="memory-desc doclib-desc" style="margin:4px 0 6px;">
|
||||||
Import a <code>.txt</code>, <code>.md</code>, <code>.pdf</code>, <code>.csv</code>, <code>.log</code>, <code>.json</code>, <code>.py</code>, <code>.js</code>, or <code>.html</code> file — the AI reads it and suggests candidate memories you can approve. Needs an open chat session (it uses that session's model).
|
Import a <code>.txt</code>, <code>.md</code>, <code>.pdf</code>, <code>.csv</code>, <code>.log</code>, <code>.json</code>, <code>.py</code>, <code>.js</code>, or <code>.html</code> file — the AI reads it and suggests candidate memories you can approve.
|
||||||
</p>
|
</p>
|
||||||
<div class="memory-add-row" style="margin-top:8px;">
|
<div class="memory-add-row" style="margin-top:8px;">
|
||||||
<div class="skill-ph-wrap" style="flex:1;min-width:0;">
|
<div class="skill-ph-wrap" style="flex:1;min-width:0;">
|
||||||
@@ -1390,7 +1390,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="admin-card">
|
<div class="admin-card">
|
||||||
<h2 style="display:flex;align-items:center;gap:6px;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:1px;opacity:0.6;flex-shrink:0"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>Utility Model <span style="font-size:0.72em;opacity:0.55;font-weight:normal;">(Recommended: Local Endpoint)</span></h2>
|
<h2 style="display:flex;align-items:center;gap:6px;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:1px;opacity:0.6;flex-shrink:0"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>Utility Model <span style="font-size:0.72em;opacity:0.55;font-weight:normal;">(Recommended: Local Endpoint)</span></h2>
|
||||||
<div class="admin-toggle-sub" style="margin-bottom:8px">Runs background tasks (compaction, cleanup, auto-naming) on a small/local model instead of your chat model. Leave blank to use the chat model.</div>
|
<div class="admin-toggle-sub" style="margin-bottom:8px">Runs background tasks (compaction, cleanup, auto-naming, retrieving memories from files) on a small/local model instead of your chat model. Leave blank to use the chat model.</div>
|
||||||
<div class="settings-col">
|
<div class="settings-col">
|
||||||
<div class="settings-row">
|
<div class="settings-row">
|
||||||
<label class="settings-label">Endpoint</label>
|
<label class="settings-label">Endpoint</label>
|
||||||
|
|||||||
+3
-5
@@ -1160,10 +1160,6 @@ async function handleImportFile(file) {
|
|||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
const sessionId = sessionModule?.getCurrentSessionId?.();
|
const sessionId = sessionModule?.getCurrentSessionId?.();
|
||||||
if (!sessionId) {
|
|
||||||
showError('Open a session first — import needs an AI model');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const importBtn = document.getElementById('memory-import-btn');
|
const importBtn = document.getElementById('memory-import-btn');
|
||||||
const _origImportHtml = importBtn ? importBtn.innerHTML : '';
|
const _origImportHtml = importBtn ? importBtn.innerHTML : '';
|
||||||
@@ -1180,7 +1176,9 @@ async function handleImportFile(file) {
|
|||||||
try {
|
try {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
formData.append('session', sessionId);
|
if (sessionId) {
|
||||||
|
formData.append('session', sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
const res = await fetch(`${window.location.origin}/api/memory/import`, {
|
const res = await fetch(`${window.location.origin}/api/memory/import`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
Reference in New Issue
Block a user