Skip to content

Commit

Permalink
👽
Browse files Browse the repository at this point in the history
  • Loading branch information
ghostofpokemon committed Sep 8, 2024
1 parent cfd2024 commit 7cfd2e6
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 1 deletion.
44 changes: 43 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,44 @@
# llm-deepseek
LLM plugin to access Deepseek's models

[![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/ghostofpokemon/llm-deepseek?include_prereleases)](https://github.com/ghostofpokemon/llm-deepseek/releases)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ghostofpokemon/llm-deepseek/blob/main/LICENSE)

LLM access to DeepSeek's API

## Installation

Install this plugin in the same environment as [LLM](https://llm.datasette.io/).

```bash
llm install llm-deepseek
```

## Usage

First, set an [API key](https://platform.deepseek.com/api_keys) for DeepSeek:

```bash
llm keys set deepseek
# Paste key here
```

Run `llm models` to list the models, and `llm models --options` to include a list of their options.

Run prompts like this:

```bash
llm -m deepseekchat/deepseek-chat "Describe a futuristic city on Mars"
llm -m deepseekcompletion/deepseek-chat "The AI began to dream, and in its dreams,"
llm -m deepseek-coder "Write a Python function to sort a list of numbers"
llm -m deepseek-coder-completion "Implement a binary search algorithm in Python"
```

## Development

To set up this plugin locally, first checkout the code. Then create a new virtual environment:

```bash
cd llm-deepseek
python3 -m venv venv
source venv/bin/activate
```
109 changes: 109 additions & 0 deletions llm_deepseek.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import llm
from llm.default_plugins.openai_models import Chat, Completion
from pathlib import Path
import json
import time
import httpx

def get_deepseek_models():
return fetch_cached_json(
url="https://api.deepseek.com/v1/models",
path=llm.user_dir() / "deepseek_models.json",
cache_timeout=3600,
)["data"]

def get_model_ids_with_aliases(models):
return [(model['id'], []) for model in models]

class DeepSeekChat(Chat):
needs_key = "deepseek"
key_env_var = "LLM_DEEPSEEK_KEY"

def __init__(self, model_id, **kwargs):
super().__init__(model_id, **kwargs)
self.api_base = "https://api.deepseek.com/beta" # Use beta API

def __str__(self):
return f"DeepSeek Chat: {self.model_id}"

class DeepSeekCompletion(Completion):
needs_key = "deepseek"
key_env_var = "LLM_DEEPSEEK_KEY"

def __init__(self, model_id, **kwargs):
super().__init__(model_id, **kwargs)
self.api_base = "https://api.deepseek.com/beta" # Use beta API

def __str__(self):
return f"DeepSeek Completion: {self.model_id}"

@llm.hookimpl
def register_models(register):
key = llm.get_key("", "deepseek", "LLM_DEEPSEEK_KEY")
if not key:
return
try:
models = get_deepseek_models()
models_with_aliases = get_model_ids_with_aliases(models)
for model_id, aliases in models_with_aliases:
register(
DeepSeekChat(
model_id=f"deepseekchat/{model_id}",
model_name=model_id,
),
aliases=[model_id]
)
register(
DeepSeekCompletion(
model_id=f"deepseekcompletion/{model_id}",
model_name=model_id,
),
aliases=[f"{model_id}-completion"]
)
except DownloadError as e:
print(f"Error fetching DeepSeek models: {e}")

class DownloadError(Exception):
pass

def fetch_cached_json(url, path, cache_timeout, headers=None):
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)

if path.is_file() and time.time() - path.stat().st_mtime < cache_timeout:
with open(path, "r") as file:
return json.load(file)

try:
response = httpx.get(url, headers=headers, follow_redirects=True)
response.raise_for_status()
with open(path, "w") as file:
json.dump(response.json(), file)
return response.json()
except httpx.HTTPError:
if path.is_file():
with open(path, "r") as file:
return json.load(file)
else:
raise DownloadError(f"Failed to download data and no cache is available at {path}")

@llm.hookimpl
def register_commands(cli):
@cli.command()
def deepseek_models():
"List available DeepSeek models"
key = llm.get_key("", "deepseek", "LLM_DEEPSEEK_KEY")
if not key:
print("DeepSeek API key not set. Use 'llm keys set deepseek' to set it.")
return
try:
models = get_deepseek_models()
models_with_aliases = get_model_ids_with_aliases(models)
for model_id, aliases in models_with_aliases:
print(f"DeepSeek Chat: deepseekchat/{model_id}")
print(f" Aliases: {model_id}")
print(f"DeepSeek Completion: deepseekcompletion/{model_id}")
print(f" Aliases: {model_id}-completion")
print()
except DownloadError as e:
print(f"Error fetching DeepSeek models: {e}")
25 changes: 25 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[project]
name = "llm-deepseek"
version = "0.1.0"
description = "LLM access to DeepSeek's API"
readme = "README.md"
license = { file = "LICENSE" }
classifiers = ["License :: OSI Approved :: Apache Software License"]
requires-python = ">=3.8"
dependencies = ["llm", "httpx"]
authors = [{ name = "Nick Mystic" }]

[project.urls]
Homepage = "https://github.com/ghostofpokemon/llm-deepseek"
Changelog = "https://github.com/ghostofpokemon/llm-deepseek/blob/main/CHANGELOG.md"
Issues = "https://github.com/ghostofpokemon/llm-deepseek/issues"
CI = "https://github.com/ghostofpokemon/llm-deepseek/actions"

[project.entry-points.llm]
deepseek = "llm_deepseek"

[project.optional-dependencies]
test = ["pytest", "pytest-httpx"]

[tool.pytest.ini_options]
filterwarnings = ["ignore::DeprecationWarning"]

0 comments on commit 7cfd2e6

Please sign in to comment.