Skip to content

Commit

Permalink
[NEW] Demo write commercial email
Browse files Browse the repository at this point in the history
  • Loading branch information
synw committed Jan 10, 2024
1 parent b6dcc53 commit d44fbc6
Show file tree
Hide file tree
Showing 15 changed files with 224 additions and 54 deletions.
4 changes: 3 additions & 1 deletion apps/llm/lm.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ def iter_stream():
token = event["choices"][0]["text"]
if LM.is_verbose is True:
print(token, end="", flush=True)
yield f"data: {token}\n\n"
payload = f"data: {token}\n\n"
# print(payload.replace("\n", "\\n"))
yield payload
i += 1

return iter_stream
9 changes: 8 additions & 1 deletion apps/llm/urls.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
from django.urls import path
from .views import infer_view, generate_view, load_model_view, models_conf_views
from .views import (
infer_view,
generate_view,
load_model_view,
models_conf_views,
execute_task_view,
)


urlpatterns = [
path("infer/", infer_view),
path("generate/", generate_view),
path("models/", models_conf_views),
path("load_model/", load_model_view),
path("task/", execute_task_view),
]
25 changes: 25 additions & 0 deletions apps/llm/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from django.views.decorators.csrf import csrf_exempt
from locallm import InferenceParams

from apps.llm.models.task import LmTask

from .lm import infer, generate, load_model, LM
from .utils import load_models_conf

Expand Down Expand Up @@ -107,3 +109,26 @@ def models_conf_views(request: HttpRequest) -> JsonResponse:
res["ctx"] = res["models"][LM.loaded_model]["ctx"] # type: ignore
print(res)
return JsonResponse(res)


@csrf_exempt
def execute_task_view(request: HttpRequest) -> JsonResponse | HttpResponseBadRequest:
if request.method == "POST": # type: ignore
body_unicode = request.body.decode("utf-8")
body = json.loads(body_unicode)
task_name = body["name"]
prompt = body["prompt"]
else:
print(
"Provide a prompt and task name: post a payload of this format: "
'{"prompt": "...", "name": "..."}'
)
return HttpResponseBadRequest("Provide a prompt and task name")
try:
task = LmTask.objects.get(name=task_name)
except LmTask.ObjectDoesNotExist:
print("Unknown task")
return HttpResponseBadRequest("Unknown task")
tpl = task.template.replace("{prompt}", prompt)
res = infer(tpl, task.params)
return JsonResponse(res)
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"djangoinstant": "^0.5.0",
"primeicons": "^6.0.1",
"primevue": "^3.27.0",
"restmix": "^0.3.1",
"restmix": "^0.4.2",
"vue": "^3.2.47",
"vue-router": "4.1.6"
},
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div :class="{ dark: user.isDarkMode.value == true }">
<div class="flex flex-col h-full min-h-screen lightbg">
<the-header></the-header>
<div class="flex-grow w-full pb-24">
<div class="flex-grow w-full pb-24 mt-16">
<router-view></router-view>
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/TheHeader.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<sw-header class="z-10 w-full h-16 lg:h-16 primary"
<sw-header class="z-10 w-full h-16 lg:h-16 primary fixed"
:class="$router.currentRoute.value.path == '/' ? 'bg-transparent' : 'primary'"
@togglemenu="isMenuVisible = !isMenuVisible" breakpoint="lg">
<template #mobile-back>
Expand All @@ -9,7 +9,7 @@
<div class="inline-flex flex-row items-center h-full pt-1 ml-2 text-2xl truncate" @click="$router.push('/')">
<div v-if="isHome" class="flex flex-row items-center h-full">
<i-fluent-emoji-high-contrast:llama class="mx-3 text-3xl"></i-fluent-emoji-high-contrast:llama>
<div class="text-2xl txt-lighter">Django Local Language Model</div>
<div class="text-2xl txt-lighter">Django Llm</div>
</div>
<div v-else v-html="$router.currentRoute.value.meta?.title"></div>
</div>
Expand Down Expand Up @@ -37,7 +37,7 @@
<div>
<button class="border-none btn" @click="user.toggleDarkMode(); closeMenu()">
<template v-if="!user.isDarkMode.value">
<i-fa-solid:moon></i-fa-solid:moon> Dark mode
<i-fa-solid:moon></i-fa-solid:moon>&nbsp;Dark mode
</template>
<template v-else>
<i-fa-solid:sun></i-fa-solid:sun> Light mode
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@ const baseTitle = "Django local AI"
const routes: Array<RouteRecordRaw> = [
{
path: "/",
component: HomeView,
//component: HomeView,
component: () => import("./views/DemoView.vue"),
meta: {
title: "Home"
title: "Email commercial"
}
},
{
path: "/demo",
component: () => import("./views/DemoView.vue"),
meta: {
title: "Email commercial"
}
},
]
Expand Down
115 changes: 115 additions & 0 deletions frontend/src/views/DemoView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<template>
<div class="w-full flex justify-center p-5">
<div class="flex flex-col max-w-[45rem]">
<div class="text-xl">Ecrire un email de prospection commerciale</div>
<div class="mt-5">
<span class="p-float-label">
<InputText id="theme" type="text" v-model="theme" />
<label for="username">Theme</label>
</span>
</div>
<div>
<div class="mt-3">
Agissez comme un directeur marketng. Ecrivez un email de prospection commerciale à un client pour une prestation
{{ theme }} sur la base de ces informations:
</div>
</div>
<div class="flex flex-col max-w-[45rem]">
<div class="pt-8">
<span class="p-float-label">
<Textarea id="prompt" v-model="prompt" rows="5" class="w-full" autoResize />
<label for="prompt">Prompt</label>
</span>
</div>
<div class="pt-5 text-center">
<button class="w-full btn secondary" @click="infer()" v-if="!lmState.isStreaming == true"
:disabled="lmState.isRunning == true || prompt.length == 0">Envoyer</button>
</div>
<div v-if="lmState.isRunning == true && lmState.isStreaming == false">
<LoadingSpinner class="pt-16 text-6xl txt-lighter" />
</div>
<div v-if="lmState.isStreaming == true">
<button class="btn danger" @click="abort()">Stop</button>
</div>
<div class="mt-8 text-justify">
<div v-html="stream.replaceAll('\n', '<br />').replaceAll('\t', '&nbsp;&nbsp;')"></div>
</div>
</div>
</div>
</div>
</template>

<script setup lang="ts">
import { ref, onBeforeMount, reactive, nextTick } from 'vue';
import Textarea from 'primevue/textarea';
import { api } from '@/state';
import LoadingSpinner from '@/widgets/LoadingSpinner.vue';
import InputText from 'primevue/inputtext';
const template = `<s>[INST] <<SYS>>
Vous êtes Vigogne, un assistant IA créé par Zaion Lab. Vous suivez extrêmement bien les instructions. Aidez autant que vous le pouvez.
<</SYS>>
Agissez comme un directeur marketng. Ecrivez un email de prospection commerciale à un client pour une prestation {theme} sur la base de ces informations:
{prompt} [/INST]`;
const prompt = ref(`Emencia Django Consulting
EXPERTS PYTHON ET DJANGO DEPUIS 2002, NOUS CRÉONS DES APPLICATIONS MÉTIERS SUR MESURE, ROBUSTES ET SÉCURISÉES
Depuis 2002, Emencia est au coeur des problématiques et des stratégies digitales des entreprises.
Nos consultants interviennent sur l’ensemble des phases d’un projet : accompagnement, architecture, gestion de projet, conception & développement, administration et mise en production applicative.
Nous mettons à disposition de nos clients un service sur mesure : conseils et audit, UI/UX, développement et intégration, Data pipelines Analytics,Cloud infogéré et Devops et TMA & support, Sourcing de Talents.`);
const theme = ref("ML Ops");
const result = ref("");
const stream = ref("");
const lmState = reactive({
isRunning: false,
isStreaming: false,
})
let i = 0;
const onChunk = (payload: Record<string, any>) => {
console.log(">>", payload);
nextTick(() => {
window.scrollTo({
top: document.body.scrollHeight,
behavior: 'smooth'
});
});
if (i == 0) {
lmState.isStreaming = true
}
if (payload["num"] == 1) {
lmState.isStreaming = true;
}
stream.value += payload
++i
};
const abortController = new AbortController();
async function infer() {
stream.value = "";
lmState.isRunning = true;
let tpl = template.replace("{theme}", theme.value);
tpl = tpl.replace("{prompt}", prompt.value);
await api.postSse<Record<string, any>>(
"/llm/generate/",
{ prompt: tpl, params: { temperature: 0.2, max_tokens: -1 } },
onChunk,
abortController,
false,
false,
true,
false,
)
lmState.isStreaming = false;
lmState.isRunning = false;
}
function abort() {
abortController.abort();
lmState.isStreaming = false;
lmState.isRunning = false;
}
onBeforeMount(() => result.value = "")
</script>
Binary file modified llmdb.sqlite3
Binary file not shown.
3 changes: 2 additions & 1 deletion main/settings/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@

# llm conf
LLM_MODELS_DIR = str(BASE_DIR.parent.parent.parent / "lm/models/")
LLM_DEFAULT_MODEL = "mistral-7b-instruct-v0.1.Q4_K_M.gguf"
# LLM_DEFAULT_MODEL = "mistral-7b-instruct-v0.1.Q4_K_M.gguf"
LLM_DEFAULT_MODEL = "vigostral-7b-chat.Q4_K_M.gguf"
LLM_DEFAULT_CTX = 8192
LLM_VERBOSE = True
4 changes: 2 additions & 2 deletions main/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>App</title>
<script type="module" crossorigin src="/static/frontend/assets/index-7594b5cb.js"></script>
<link rel="stylesheet" href="/static/frontend/assets/index-697d1199.css">
<script type="module" crossorigin src="/static/frontend/assets/index-b070d0e6.js"></script>
<link rel="stylesheet" href="/static/frontend/assets/index-50520349.css">
</head>

<body>
Expand Down
23 changes: 23 additions & 0 deletions main/webapp_statics/frontend/assets/DemoView-a5fc5e1c.js

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

1 change: 1 addition & 0 deletions main/webapp_statics/frontend/assets/index-50520349.css

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion main/webapp_statics/frontend/assets/index-697d1199.css

This file was deleted.

Large diffs are not rendered by default.

0 comments on commit d44fbc6

Please sign in to comment.