-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cfd2024
commit 7cfd2e6
Showing
3 changed files
with
177 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"] |