qv-session-manager


Nameqv-session-manager JSON
Version 0.2.0 PyPI version JSON
download
home_pageNone
SummarySimple, efficient session manager for persistent storage of conversations from qv-ollama-sdk in SQLite
upload_time2025-07-31 06:36:01
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseMIT
keywords ollama session-manager conversation sqlite llm chat persistence
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # QV Session Manager

A simple, efficient session manager for persistent storage and management of conversations from [qv-ollama-sdk](https://github.com/quantyverse/qv-ollama-sdk) in an SQLite database.

## โœจ Features

- ๐Ÿ’พ **Persistent storage** of conversations and messages in SQLite
- ๐Ÿ” **Full-text search** in conversation contents and titles
- โฐ **Time-based search** by creation/update date
- ๐Ÿ”„ **Conversation resumption** at any point
- ๐Ÿ“‹ **Conversation management** (list, delete, load)
- ๐ŸŽฏ **Minimal dependencies** (only Python stdlib + qv-ollama-sdk)
- ๐Ÿš€ **Simple API** with clear, intuitive methods

## ๐Ÿ› ๏ธ Installation

### From PyPI 
```bash
pip install qv-session-manager

or

uv add qv-session-manager
```

### Development installation
```bash
git clone https://github.com/quantyverse/qv-session-manager.git
cd qv-session-manager
pip install -e .
```

### Dependencies
- Python 3.10+
- qv-ollama-sdk

## ๐Ÿš€ Quickstart

```python
from qv_session_manager import SessionManager
from qv_ollama_sdk.domain.models import Conversation

# Initialize SessionManager
mgr = SessionManager(db_path="my_sessions.db")

# Create new conversation
conv = Conversation(title="Python Help", model_name="llama3")
conv.add_user_message("Explain Python lists to me!")
conv.add_assistant_message("Lists are ordered, mutable collections...")

# Save
mgr.save_conversation(conv, conv.messages)

# Load
loaded = mgr.load_conversation(str(conv.id))
print(f"Loaded: {loaded.title} with {len(loaded.messages)} messages")

# Search
results = mgr.search_conversations("lists")
print(f"Found: {len(results)} conversations")
```

## ๐Ÿ“š API Documentation

### SessionManager

#### Initialization
```python
SessionManager(db_path: str = "session_manager.db")
```
- `db_path`: Path to the SQLite database file

#### Methods

##### `save_conversation(conversation, messages)`
Saves a conversation and its messages.
- `conversation`: Conversation object (with `to_db_dict()` method)
- `messages`: List of Message objects (with `to_db_dict()` methods)

```python
mgr.save_conversation(conv, conv.messages)
```

##### `load_conversation(conversation_id: str) -> Conversation | None`
Loads a conversation with all messages.
- `conversation_id`: UUID of the conversation as a string
- **Returns**: Conversation object or None

```python
conv = mgr.load_conversation("550e8400-e29b-41d4-a716-446655440000")
```

##### `list_conversations() -> List[Dict[str, Any]]`
Lists all conversations (without messages).
- **Returns**: List of conversation dicts with metadata

```python
all_convs = mgr.list_conversations()
for conv in all_convs:
    print(f"{conv['title']} - {conv['created_at']}")
```

##### `search_conversations(query: str) -> List[Dict[str, Any]]`
Full-text search in titles and message contents.
- `query`: Search term
- **Returns**: List of found conversation dicts

```python
results = mgr.search_conversations("Python")
```

##### `search_by_time(start: str = None, end: str = None) -> List[Dict[str, Any]]`
Time-based search for conversations.
- `start`: Start date (ISO format, e.g. "2025-01-20")
- `end`: End date (ISO format)
- **Returns**: List of conversation dicts

```python
# Conversations from today
today = datetime.now().strftime("%Y-%m-%d")
recent = mgr.search_by_time(start=today)

# Conversations from a period
results = mgr.search_by_time(start="2025-01-01", end="2025-01-31")
```

##### `resume_conversation(conversation_id: str) -> Dict[str, Any] | None`
Prepares conversation resumption.
- `conversation_id`: UUID of the conversation
- **Returns**: Dict with `conversation` and `last_message`

```python
resumed = mgr.resume_conversation(str(conv.id))
last_msg = resumed["last_message"]
print(f"Last message: {last_msg['content']}")
```

##### `delete_conversation(conversation_id: str)`
Deletes a conversation and all associated messages.
- `conversation_id`: UUID of the conversation

```python
mgr.delete_conversation(str(conv.id))
```

## ๐Ÿ’ก Advanced Examples

### Conversation management with metadata

```python
from datetime import datetime
from qv_session_manager import SessionManager
from qv_ollama_sdk.domain.models import Conversation

mgr = SessionManager()

# Conversation with metadata
conv = Conversation(
    title="JavaScript Tutorial",
    model_name="llama3",
    metadata={
        "topic": "web-development", 
        "difficulty": "beginner",
        "language": "javascript"
    }
)

# Add messages
conv.add_system_message("You are an experienced web developer.")
conv.add_user_message("Explain closures in JavaScript.")

# Save
mgr.save_conversation(conv, conv.messages)

# Search by topic
web_convs = [c for c in mgr.list_conversations() 
             if c.get('metadata', {}).get('topic') == 'web-development']
```

### Batch operations

```python
# Delete all conversations from a specific day
target_date = "2025-01-20"
old_convs = mgr.search_by_time(start=target_date, end=target_date)

for conv in old_convs:
    mgr.delete_conversation(conv['id'])
    print(f"Deleted: {conv['title']}")
```

### Conversation continuation

```python
# Load and extend an existing conversation
conv = mgr.load_conversation("existing-conversation-id")

if conv:
    # Add new messages
    conv.add_user_message("Can you explain that again?")
    conv.add_assistant_message("Sure! Let me rephrase that...")
    
    # Save updated version
    mgr.save_conversation(conv, conv.messages)
```

## ๐Ÿงช Development & Testing

### Run tests
```bash
# All tests
pytest

# Specific test
pytest tests/test_session_manager.py

# With output
pytest -v -s
```

### Run demo
```bash
python examples/basic_usage.py
```

### Project structure
```
qv-session-manager/
โ”œโ”€โ”€ src/qv_session_manager/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ session_manager.py
โ”œโ”€โ”€ tests/
โ”‚   โ””โ”€โ”€ test_session_manager.py
โ”œโ”€โ”€ examples/
โ”‚   โ””โ”€โ”€ basic_usage.py
โ”œโ”€โ”€ README.md
โ””โ”€โ”€ pyproject.toml
```

## ๐Ÿ—„๏ธ Database Schema

The SQLite database uses the following schema:

```sql
-- Conversations table
CREATE TABLE conversations (
    id TEXT PRIMARY KEY,           -- UUID
    title TEXT,                    -- Conversation title
    created_at TEXT,              -- ISO timestamp
    updated_at TEXT,              -- ISO timestamp  
    metadata TEXT                 -- JSON metadata
);

-- Messages table
CREATE TABLE messages (
    id TEXT PRIMARY KEY,          -- UUID
    conversation_id TEXT,         -- Reference to conversations.id
    role TEXT,                    -- "system", "user", "assistant"
    content TEXT,                 -- Message content
    created_at TEXT,             -- ISO timestamp
    metadata TEXT,               -- JSON metadata
    FOREIGN KEY(conversation_id) REFERENCES conversations(id) ON DELETE CASCADE
);
```

## ๐Ÿค Integration with qv-ollama-sdk

```python
from qv_ollama_sdk.client import OllamaClient
from qv_session_manager import SessionManager

# Initialize clients
ollama = OllamaClient()
session_mgr = SessionManager()

# New conversation
conv = ollama.create_conversation(model="gemma3:1b")
conv.title = "Code Review Session"

# Chat with Ollama
response = ollama.chat(conv, "Explain Clean Code principles to me")
print(response.content)

# Persist session
session_mgr.save_conversation(conv, conv.messages)

# Later: load and continue session
loaded_conv = session_mgr.load_conversation(str(conv.id))
next_response = ollama.chat(loaded_conv, "Which tools do you recommend?")
```

## ๐Ÿ“‹ Roadmap

- [ ] Advanced search/filter functions (e.g. by metadata)
- [ ] Optional encryption of stored data
- [ ] Export/import of conversations (JSON, CSV)
- [ ] Performance optimizations for large datasets
- [ ] Async support for high-performance applications

## ๐Ÿ› Error Handling

```python
try:
    conv = mgr.load_conversation("invalid-id")
    if conv is None:
        print("Conversation not found")
except Exception as e:
    print(f"Error loading: {e}")
```

## ๐Ÿ“„ License

MIT License - see [LICENSE](LICENSE) for details.


## ๐Ÿ“ž Support

- **Issues**: [GitHub Issues](https://github.com/quantyverse/qv-session-manager/issues)
- **Documentation**: This README
- **Examples**: See the `examples/` directory

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "qv-session-manager",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": "Thomas Bernhard <thomas@quantyverse.com>",
    "keywords": "ollama, session-manager, conversation, sqlite, llm, chat, persistence",
    "author": null,
    "author_email": "Thomas Bernhard <thomas@quantyverse.com>",
    "download_url": "https://files.pythonhosted.org/packages/04/57/5c601a6d12f2318c5fde913077b44a18f7726f903244a2cd728eec3c4c64/qv_session_manager-0.2.0.tar.gz",
    "platform": null,
    "description": "# QV Session Manager\r\n\r\nA simple, efficient session manager for persistent storage and management of conversations from [qv-ollama-sdk](https://github.com/quantyverse/qv-ollama-sdk) in an SQLite database.\r\n\r\n## \u2728 Features\r\n\r\n- \ud83d\udcbe **Persistent storage** of conversations and messages in SQLite\r\n- \ud83d\udd0d **Full-text search** in conversation contents and titles\r\n- \u23f0 **Time-based search** by creation/update date\r\n- \ud83d\udd04 **Conversation resumption** at any point\r\n- \ud83d\udccb **Conversation management** (list, delete, load)\r\n- \ud83c\udfaf **Minimal dependencies** (only Python stdlib + qv-ollama-sdk)\r\n- \ud83d\ude80 **Simple API** with clear, intuitive methods\r\n\r\n## \ud83d\udee0\ufe0f Installation\r\n\r\n### From PyPI \r\n```bash\r\npip install qv-session-manager\r\n\r\nor\r\n\r\nuv add qv-session-manager\r\n```\r\n\r\n### Development installation\r\n```bash\r\ngit clone https://github.com/quantyverse/qv-session-manager.git\r\ncd qv-session-manager\r\npip install -e .\r\n```\r\n\r\n### Dependencies\r\n- Python 3.10+\r\n- qv-ollama-sdk\r\n\r\n## \ud83d\ude80 Quickstart\r\n\r\n```python\r\nfrom qv_session_manager import SessionManager\r\nfrom qv_ollama_sdk.domain.models import Conversation\r\n\r\n# Initialize SessionManager\r\nmgr = SessionManager(db_path=\"my_sessions.db\")\r\n\r\n# Create new conversation\r\nconv = Conversation(title=\"Python Help\", model_name=\"llama3\")\r\nconv.add_user_message(\"Explain Python lists to me!\")\r\nconv.add_assistant_message(\"Lists are ordered, mutable collections...\")\r\n\r\n# Save\r\nmgr.save_conversation(conv, conv.messages)\r\n\r\n# Load\r\nloaded = mgr.load_conversation(str(conv.id))\r\nprint(f\"Loaded: {loaded.title} with {len(loaded.messages)} messages\")\r\n\r\n# Search\r\nresults = mgr.search_conversations(\"lists\")\r\nprint(f\"Found: {len(results)} conversations\")\r\n```\r\n\r\n## \ud83d\udcda API Documentation\r\n\r\n### SessionManager\r\n\r\n#### Initialization\r\n```python\r\nSessionManager(db_path: str = \"session_manager.db\")\r\n```\r\n- `db_path`: Path to the SQLite database file\r\n\r\n#### Methods\r\n\r\n##### `save_conversation(conversation, messages)`\r\nSaves a conversation and its messages.\r\n- `conversation`: Conversation object (with `to_db_dict()` method)\r\n- `messages`: List of Message objects (with `to_db_dict()` methods)\r\n\r\n```python\r\nmgr.save_conversation(conv, conv.messages)\r\n```\r\n\r\n##### `load_conversation(conversation_id: str) -> Conversation | None`\r\nLoads a conversation with all messages.\r\n- `conversation_id`: UUID of the conversation as a string\r\n- **Returns**: Conversation object or None\r\n\r\n```python\r\nconv = mgr.load_conversation(\"550e8400-e29b-41d4-a716-446655440000\")\r\n```\r\n\r\n##### `list_conversations() -> List[Dict[str, Any]]`\r\nLists all conversations (without messages).\r\n- **Returns**: List of conversation dicts with metadata\r\n\r\n```python\r\nall_convs = mgr.list_conversations()\r\nfor conv in all_convs:\r\n    print(f\"{conv['title']} - {conv['created_at']}\")\r\n```\r\n\r\n##### `search_conversations(query: str) -> List[Dict[str, Any]]`\r\nFull-text search in titles and message contents.\r\n- `query`: Search term\r\n- **Returns**: List of found conversation dicts\r\n\r\n```python\r\nresults = mgr.search_conversations(\"Python\")\r\n```\r\n\r\n##### `search_by_time(start: str = None, end: str = None) -> List[Dict[str, Any]]`\r\nTime-based search for conversations.\r\n- `start`: Start date (ISO format, e.g. \"2025-01-20\")\r\n- `end`: End date (ISO format)\r\n- **Returns**: List of conversation dicts\r\n\r\n```python\r\n# Conversations from today\r\ntoday = datetime.now().strftime(\"%Y-%m-%d\")\r\nrecent = mgr.search_by_time(start=today)\r\n\r\n# Conversations from a period\r\nresults = mgr.search_by_time(start=\"2025-01-01\", end=\"2025-01-31\")\r\n```\r\n\r\n##### `resume_conversation(conversation_id: str) -> Dict[str, Any] | None`\r\nPrepares conversation resumption.\r\n- `conversation_id`: UUID of the conversation\r\n- **Returns**: Dict with `conversation` and `last_message`\r\n\r\n```python\r\nresumed = mgr.resume_conversation(str(conv.id))\r\nlast_msg = resumed[\"last_message\"]\r\nprint(f\"Last message: {last_msg['content']}\")\r\n```\r\n\r\n##### `delete_conversation(conversation_id: str)`\r\nDeletes a conversation and all associated messages.\r\n- `conversation_id`: UUID of the conversation\r\n\r\n```python\r\nmgr.delete_conversation(str(conv.id))\r\n```\r\n\r\n## \ud83d\udca1 Advanced Examples\r\n\r\n### Conversation management with metadata\r\n\r\n```python\r\nfrom datetime import datetime\r\nfrom qv_session_manager import SessionManager\r\nfrom qv_ollama_sdk.domain.models import Conversation\r\n\r\nmgr = SessionManager()\r\n\r\n# Conversation with metadata\r\nconv = Conversation(\r\n    title=\"JavaScript Tutorial\",\r\n    model_name=\"llama3\",\r\n    metadata={\r\n        \"topic\": \"web-development\", \r\n        \"difficulty\": \"beginner\",\r\n        \"language\": \"javascript\"\r\n    }\r\n)\r\n\r\n# Add messages\r\nconv.add_system_message(\"You are an experienced web developer.\")\r\nconv.add_user_message(\"Explain closures in JavaScript.\")\r\n\r\n# Save\r\nmgr.save_conversation(conv, conv.messages)\r\n\r\n# Search by topic\r\nweb_convs = [c for c in mgr.list_conversations() \r\n             if c.get('metadata', {}).get('topic') == 'web-development']\r\n```\r\n\r\n### Batch operations\r\n\r\n```python\r\n# Delete all conversations from a specific day\r\ntarget_date = \"2025-01-20\"\r\nold_convs = mgr.search_by_time(start=target_date, end=target_date)\r\n\r\nfor conv in old_convs:\r\n    mgr.delete_conversation(conv['id'])\r\n    print(f\"Deleted: {conv['title']}\")\r\n```\r\n\r\n### Conversation continuation\r\n\r\n```python\r\n# Load and extend an existing conversation\r\nconv = mgr.load_conversation(\"existing-conversation-id\")\r\n\r\nif conv:\r\n    # Add new messages\r\n    conv.add_user_message(\"Can you explain that again?\")\r\n    conv.add_assistant_message(\"Sure! Let me rephrase that...\")\r\n    \r\n    # Save updated version\r\n    mgr.save_conversation(conv, conv.messages)\r\n```\r\n\r\n## \ud83e\uddea Development & Testing\r\n\r\n### Run tests\r\n```bash\r\n# All tests\r\npytest\r\n\r\n# Specific test\r\npytest tests/test_session_manager.py\r\n\r\n# With output\r\npytest -v -s\r\n```\r\n\r\n### Run demo\r\n```bash\r\npython examples/basic_usage.py\r\n```\r\n\r\n### Project structure\r\n```\r\nqv-session-manager/\r\n\u251c\u2500\u2500 src/qv_session_manager/\r\n\u2502   \u251c\u2500\u2500 __init__.py\r\n\u2502   \u2514\u2500\u2500 session_manager.py\r\n\u251c\u2500\u2500 tests/\r\n\u2502   \u2514\u2500\u2500 test_session_manager.py\r\n\u251c\u2500\u2500 examples/\r\n\u2502   \u2514\u2500\u2500 basic_usage.py\r\n\u251c\u2500\u2500 README.md\r\n\u2514\u2500\u2500 pyproject.toml\r\n```\r\n\r\n## \ud83d\uddc4\ufe0f Database Schema\r\n\r\nThe SQLite database uses the following schema:\r\n\r\n```sql\r\n-- Conversations table\r\nCREATE TABLE conversations (\r\n    id TEXT PRIMARY KEY,           -- UUID\r\n    title TEXT,                    -- Conversation title\r\n    created_at TEXT,              -- ISO timestamp\r\n    updated_at TEXT,              -- ISO timestamp  \r\n    metadata TEXT                 -- JSON metadata\r\n);\r\n\r\n-- Messages table\r\nCREATE TABLE messages (\r\n    id TEXT PRIMARY KEY,          -- UUID\r\n    conversation_id TEXT,         -- Reference to conversations.id\r\n    role TEXT,                    -- \"system\", \"user\", \"assistant\"\r\n    content TEXT,                 -- Message content\r\n    created_at TEXT,             -- ISO timestamp\r\n    metadata TEXT,               -- JSON metadata\r\n    FOREIGN KEY(conversation_id) REFERENCES conversations(id) ON DELETE CASCADE\r\n);\r\n```\r\n\r\n## \ud83e\udd1d Integration with qv-ollama-sdk\r\n\r\n```python\r\nfrom qv_ollama_sdk.client import OllamaClient\r\nfrom qv_session_manager import SessionManager\r\n\r\n# Initialize clients\r\nollama = OllamaClient()\r\nsession_mgr = SessionManager()\r\n\r\n# New conversation\r\nconv = ollama.create_conversation(model=\"gemma3:1b\")\r\nconv.title = \"Code Review Session\"\r\n\r\n# Chat with Ollama\r\nresponse = ollama.chat(conv, \"Explain Clean Code principles to me\")\r\nprint(response.content)\r\n\r\n# Persist session\r\nsession_mgr.save_conversation(conv, conv.messages)\r\n\r\n# Later: load and continue session\r\nloaded_conv = session_mgr.load_conversation(str(conv.id))\r\nnext_response = ollama.chat(loaded_conv, \"Which tools do you recommend?\")\r\n```\r\n\r\n## \ud83d\udccb Roadmap\r\n\r\n- [ ] Advanced search/filter functions (e.g. by metadata)\r\n- [ ] Optional encryption of stored data\r\n- [ ] Export/import of conversations (JSON, CSV)\r\n- [ ] Performance optimizations for large datasets\r\n- [ ] Async support for high-performance applications\r\n\r\n## \ud83d\udc1b Error Handling\r\n\r\n```python\r\ntry:\r\n    conv = mgr.load_conversation(\"invalid-id\")\r\n    if conv is None:\r\n        print(\"Conversation not found\")\r\nexcept Exception as e:\r\n    print(f\"Error loading: {e}\")\r\n```\r\n\r\n## \ud83d\udcc4 License\r\n\r\nMIT License - see [LICENSE](LICENSE) for details.\r\n\r\n\r\n## \ud83d\udcde Support\r\n\r\n- **Issues**: [GitHub Issues](https://github.com/quantyverse/qv-session-manager/issues)\r\n- **Documentation**: This README\r\n- **Examples**: See the `examples/` directory\r\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Simple, efficient session manager for persistent storage of conversations from qv-ollama-sdk in SQLite",
    "version": "0.2.0",
    "project_urls": {
        "Documentation": "https://github.com/quantyverse/qv-session-manager#readme",
        "Homepage": "https://quantyverse.ai",
        "Issues": "https://github.com/quantyverse/qv-session-manager/issues",
        "Repository": "https://github.com/quantyverse/qv-session-manager.git"
    },
    "split_keywords": [
        "ollama",
        " session-manager",
        " conversation",
        " sqlite",
        " llm",
        " chat",
        " persistence"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "8c69e3d70e6574602d6165cceef78db12d62565753e5d5d2cb415f3ee3d686e3",
                "md5": "350fcdf3916e09da02ab438fbed6cc9a",
                "sha256": "9cb6b3d24053f99f98002661bb7675842cb900ac7ae8d86d63e55035a3013e99"
            },
            "downloads": -1,
            "filename": "qv_session_manager-0.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "350fcdf3916e09da02ab438fbed6cc9a",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 7681,
            "upload_time": "2025-07-31T06:36:00",
            "upload_time_iso_8601": "2025-07-31T06:36:00.189105Z",
            "url": "https://files.pythonhosted.org/packages/8c/69/e3d70e6574602d6165cceef78db12d62565753e5d5d2cb415f3ee3d686e3/qv_session_manager-0.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "04575c601a6d12f2318c5fde913077b44a18f7726f903244a2cd728eec3c4c64",
                "md5": "ab1c624559a485bf78e1f8b841ceb738",
                "sha256": "f6bf535422ba56b678763df05f42056bf7ff6ca9f3729d61cbe37b36ec76b6f2"
            },
            "downloads": -1,
            "filename": "qv_session_manager-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "ab1c624559a485bf78e1f8b841ceb738",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 11089,
            "upload_time": "2025-07-31T06:36:01",
            "upload_time_iso_8601": "2025-07-31T06:36:01.611421Z",
            "url": "https://files.pythonhosted.org/packages/04/57/5c601a6d12f2318c5fde913077b44a18f7726f903244a2cd728eec3c4c64/qv_session_manager-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-31 06:36:01",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "quantyverse",
    "github_project": "qv-session-manager#readme",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "qv-session-manager"
}
        
Elapsed time: 0.81962s