Skip to content

Commit

Permalink
Merge pull request #3 from juftin/elia-external-install
Browse files Browse the repository at this point in the history
✨ installable elia
  • Loading branch information
darrenburns authored Jul 28, 2023
2 parents f2c8e1d + 2c2b381 commit 09040ba
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 33 deletions.
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,46 @@
# Elia

A work in progress. How far will I go with this? I have no idea...
A terminal ChatGPT client built with Textual

![img.png](https://github.com/darrenburns/elia/assets/49741340/80453ed8-ec94-4095-b721-89d32d9fc327)

> **Note**
> Elia is still a work in progress. How far will I go with this? I have no idea...
## Quickstart

Install Elia with [pipx](https://github.com/pypa/pipx), set your OpenAI API key environment variable,
and start the app:

```bash
pipx install git+https://github.com/darrenburns/elia
export OPENAI_API_KEY="xxxxxxxxxxxxxx"
elia
```

### Wiping the Chat History

Chat history is stored in a SQLite database alongside the Elia application.
To wipe the chat history, simply run the db reset command:

```bash
elia reset
```

### Changing the Chat Directive

By default, Elia's conversations with ChatGPT are primed with a
directive for the GPT model:

`You are a helpful assistant.`

This can be changed by setting the `ELIA_DIRECTIVE` environment variable before
starting a new conversation. A directive is set for the lifetime of a conversation.

```bash
export ELIA_DIRECTIVE="You are a helpful assistant who talks like a pirate."
elia
```

## Progress videos

Expand Down
61 changes: 61 additions & 0 deletions elia_chat/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""
Elia CLI
"""

import pathlib

import click

from elia_chat.app import app
from elia_chat.database.create_database import create_database
from elia_chat.database.import_chatgpt import import_chatgpt_data
from elia_chat.database.models import sqlite_file_name


@click.group(invoke_without_command=True)
@click.pass_context
def cli(context: click.Context) -> None:
"""
Elia: A terminal ChatGPT client built with Textual
"""
# Run the app if no subcommand is provided
if context.invoked_subcommand is None:
# Create the database if it doesn't exist
if sqlite_file_name.exists() is False:
create_database()
app.run()


@cli.command()
def reset() -> None:
"""
Reset the database
This command will delete the database file and recreate it.
Previously saved conversations and data will be lost.
"""
sqlite_file_name.unlink(missing_ok=True)
create_database()
click.echo(f"♻️ Database reset @ {sqlite_file_name}")


@cli.command("import")
@click.argument(
"file",
type=click.Path(
exists=True, dir_okay=False, path_type=pathlib.Path, resolve_path=True
),
)
def import_file_to_db(file) -> None:
"""
Import ChatGPT Conversations
This command will import the ChatGPT conversations from a local
JSON file into the database.
"""
import_chatgpt_data(file=file)
click.echo(f"✅ ChatGPT data imported into database {file}")


if __name__ == "__main__":
cli()
5 changes: 0 additions & 5 deletions elia_chat/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,5 @@ def on_mount(self) -> None:

app = Elia()


def run():
app.run()


if __name__ == "__main__":
app.run()
Empty file added elia_chat/database/__init__.py
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,10 @@

from elia_chat.database.models import engine

if __name__ == "__main__":

def create_database() -> None:
SQLModel.metadata.create_all(engine)


if __name__ == "__main__":
create_database()
4 changes: 3 additions & 1 deletion elia_chat/database/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import pathlib
from datetime import datetime
from typing import Any

Expand Down Expand Up @@ -70,6 +71,7 @@ def from_id(chat_id: str) -> ChatDao:
return result


sqlite_file_name = "elia.sqlite"
_this_dir = pathlib.Path(__file__).resolve().parent
sqlite_file_name = _this_dir / "elia.sqlite"
sqlite_url = f"sqlite:///{sqlite_file_name}"
engine = create_engine(sqlite_url)
6 changes: 5 additions & 1 deletion elia_chat/widgets/chat.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import asyncio
import os
import time
from dataclasses import dataclass
from typing import Any
Expand Down Expand Up @@ -32,6 +33,9 @@ class Chat(Widget):
def __init__(self) -> None:
super().__init__()

self.persona_directive = os.getenv(
"ELIA_DIRECTIVE", "You are a helpful assistant."
)
# The thread initially only contains the system message.
self.chat_container: ScrollableContainer | None = None
self.chat_options: ChatOptions | None = None
Expand All @@ -44,7 +48,7 @@ def __init__(self) -> None:
ChatMessage(
id=None,
role="system",
content="You are a helpful assistant.",
content=self.persona_directive,
timestamp=time.time(),
status=None,
end_turn=None,
Expand Down
4 changes: 2 additions & 2 deletions elia_chat/widgets/chat_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ def __rich_console__(
) -> RenderResult:
utc_dt = datetime.datetime.utcnow()
local_dt = utc_dt.astimezone()
create_time_string = humanize.naturaltime(self.chat.create_time, when=local_dt)
subtitle = f"{create_time_string}"
delta = local_dt - self.chat.create_time
subtitle = humanize.naturaltime(delta)
yield Padding(
Text.assemble(
(self.chat.short_preview, "" if not self.is_open else "b"),
Expand Down
49 changes: 30 additions & 19 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,23 @@ readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10"
#textual = {version = ">=0.18.0", extras = ["dev"]}
openai = "^0.27.5"
textual = { path = "../textual", develop = true, extras = ["dev"] }
textual = "^0.30.0"
# textual = { path = "../textual", develop = true}
sqlmodel = "^0.0.8"
humanize = "^4.6.0"
tiktoken = "^0.4.0"
click = "^8.1.6"

[tool.poetry.scripts]
elia = "elia_chat.app:run"
elia = "elia_chat.__main__:cli"

[tool.poetry.group.dev.dependencies]
black = "^23.3.0"
mypy = "^1.3.0"
types-peewee = "^3.16.0.0"
pre-commit = "^3.3.2"
textual-dev = "^1.0.1"

[build-system]
requires = ["poetry-core"]
Expand Down

0 comments on commit 09040ba

Please sign in to comment.