ollama/proto.py

138 lines
3.6 KiB
Python
Raw Normal View History

2023-06-23 17:10:13 +00:00
import json
import os
2023-06-26 16:08:03 +00:00
import threading
2023-06-26 16:30:35 +00:00
import click
2023-06-23 17:10:13 +00:00
from llama_cpp import Llama
from flask import Flask, Response, stream_with_context, request
2023-06-23 22:38:22 +00:00
from flask_cors import CORS
2023-06-26 17:41:16 +00:00
from template import template
2023-06-23 17:10:13 +00:00
app = Flask(__name__)
CORS(app) # enable CORS for all routes
# llms tracks which models are loaded
llms = {}
2023-06-26 16:08:03 +00:00
lock = threading.Lock()
def load(model):
with lock:
if not os.path.exists(f"./models/{model}.bin"):
return {"error": "The model does not exist."}
if model not in llms:
llms[model] = Llama(model_path=f"./models/{model}.bin")
return None
def unload(model):
with lock:
if not os.path.exists(f"./models/{model}.bin"):
return {"error": "The model does not exist."}
llms.pop(model, None)
return None
2023-06-26 17:00:40 +00:00
def query(model, prompt):
2023-06-26 16:08:03 +00:00
# auto load
error = load(model)
if error is not None:
return error
2023-06-26 17:00:40 +00:00
generated = llms[model](
2023-06-26 16:08:03 +00:00
str(prompt), # TODO: optimize prompt based on model
max_tokens=4096,
stop=["Q:", "\n"],
echo=True,
stream=True,
)
2023-06-26 17:00:40 +00:00
for output in generated:
2023-06-26 16:08:03 +00:00
yield json.dumps(output)
def models():
all_files = os.listdir("./models")
bin_files = [
file.replace(".bin", "") for file in all_files if file.endswith(".bin")
]
return bin_files
2023-06-23 17:10:13 +00:00
2023-06-23 18:47:57 +00:00
@app.route("/load", methods=["POST"])
2023-06-26 16:08:03 +00:00
def load_route_handler():
2023-06-23 18:47:57 +00:00
data = request.get_json()
model = data.get("model")
if not model:
return Response("Model is required", status=400)
2023-06-26 16:08:03 +00:00
error = load(model)
if error is not None:
return error
2023-06-23 18:47:57 +00:00
return Response(status=204)
@app.route("/unload", methods=["POST"])
2023-06-26 16:08:03 +00:00
def unload_route_handler():
2023-06-23 18:47:57 +00:00
data = request.get_json()
model = data.get("model")
if not model:
return Response("Model is required", status=400)
2023-06-26 16:08:03 +00:00
error = unload(model)
if error is not None:
return error
2023-06-23 18:47:57 +00:00
return Response(status=204)
2023-06-23 17:10:13 +00:00
@app.route("/generate", methods=["POST"])
2023-06-26 16:08:03 +00:00
def generate_route_handler():
2023-06-23 17:10:13 +00:00
data = request.get_json()
model = data.get("model")
prompt = data.get("prompt")
if not model:
return Response("Model is required", status=400)
if not prompt:
return Response("Prompt is required", status=400)
2023-06-25 18:18:48 +00:00
if not os.path.exists(f"./models/{model}.bin"):
2023-06-23 18:47:57 +00:00
return {"error": "The model does not exist."}, 400
2023-06-23 17:10:13 +00:00
return Response(
2023-06-26 17:00:40 +00:00
stream_with_context(query(model, prompt)), mimetype="text/event-stream"
2023-06-23 17:10:13 +00:00
)
2023-06-26 16:08:03 +00:00
2023-06-25 18:22:07 +00:00
@app.route("/models", methods=["GET"])
2023-06-26 16:08:03 +00:00
def models_route_handler():
bin_files = models()
2023-06-25 18:22:07 +00:00
return Response(json.dumps(bin_files), mimetype="application/json")
2023-06-26 16:08:03 +00:00
2023-06-26 16:30:35 +00:00
@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
# allows the script to respond to command line input when executed directly
if ctx.invoked_subcommand is None:
click.echo(ctx.get_help())
@cli.command()
@click.option("--port", default=5000, help="Port to run the server on")
@click.option("--debug", default=False, help="Enable debug mode")
def serve(port, debug):
print("Serving on http://localhost:{port}")
app.run(host="0.0.0.0", port=port, debug=debug)
2023-06-26 17:00:40 +00:00
@cli.command()
@click.option("--model", default="vicuna-7b-v1.3.ggmlv3.q8_0", help="The model to use")
@click.option("--prompt", default="", help="The prompt for the model")
def generate(model, prompt):
if prompt == "":
prompt = input("Prompt: ")
output = ""
2023-06-26 17:41:16 +00:00
prompt = template(model, prompt)
2023-06-26 17:00:40 +00:00
for generated in query(model, prompt):
generated_json = json.loads(generated)
text = generated_json["choices"][0]["text"]
output += text
print(f"\r{output}", end="", flush=True)
2023-06-23 17:10:13 +00:00
if __name__ == "__main__":
2023-06-26 16:30:35 +00:00
cli()