File size: 5,627 Bytes
993e8ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12ea454
 
993e8ac
6a3db72
 
 
 
 
 
 
 
993e8ac
6a3db72
12ea454
 
 
6a3db72
 
993e8ac
 
 
 
a9a5f4b
 
993e8ac
 
6a3db72
993e8ac
 
 
 
 
6a3db72
993e8ac
6a3db72
 
 
eaf32c8
 
6a3db72
 
 
 
 
 
 
 
 
 
 
 
12ea454
6a3db72
 
 
 
 
 
 
 
 
 
 
 
a9a5f4b
01f53fe
a9a5f4b
6a3db72
993e8ac
a6fe8fb
 
993e8ac
 
 
a9a5f4b
993e8ac
6a3db72
 
 
 
 
 
 
 
 
 
 
a9a5f4b
 
 
 
 
 
993e8ac
 
 
 
 
 
 
6a3db72
 
 
 
 
 
 
 
 
 
993e8ac
6a3db72
 
 
993e8ac
6a3db72
 
 
 
 
 
 
 
 
 
 
 
a9a5f4b
 
993e8ac
6a3db72
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# The MIT License

# Copyright (c) 2025 Albert Murienne

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

import os
import spaces
import torch

import gradio as gr

from transformers import (
    AutoTokenizer, 
    AutoModelForSeq2SeqLM, 
    pipeline
)

from huggingface_hub import InferenceClient

device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"current device is: {device}")

# CHAT MODEL

class chat_engine_hf_api:

    def __init__(self):
        self.client = InferenceClient(
            "microsoft/Phi-3.5-mini-instruct",
            #"meta-llama/Llama-3.2-3B-Instruct",
            token=os.environ['HF_TOKEN_API']
        )

    def answer(self, message, history):
        return self.client.chat_completion(
            history + [{"role": "user", "content": f"tu es un assistant francophone. Répond en une seule phrase sans formattage.\n{message}"}], 
            max_tokens=512, 
            temperature = 0.5).choices[0].message.content

chat_engine = chat_engine_hf_api()

# TRANSLATION MODELS

fw_modelcard = "amurienne/gallek-m2m100-v0.2"
bw_modelcard = "amurienne/kellag-m2m100-v0.2"

fw_model = AutoModelForSeq2SeqLM.from_pretrained(fw_modelcard)
fw_tokenizer = AutoTokenizer.from_pretrained(fw_modelcard)

fw_translation_pipeline = pipeline("translation", model=fw_model, tokenizer=fw_tokenizer, src_lang='fr', tgt_lang='br', max_length=400, device="cpu")

bw_model = AutoModelForSeq2SeqLM.from_pretrained(bw_modelcard)
bw_tokenizer = AutoTokenizer.from_pretrained(bw_modelcard)

bw_translation_pipeline = pipeline("translation", model=bw_model, tokenizer=bw_tokenizer, src_lang='br', tgt_lang='fr', max_length=400, device="cpu")

# translation function
@spaces.GPU
def translate(text, forward: bool):
    if forward:
        return fw_translation_pipeline("traduis de français en breton: " + text)[0]['translation_text']
    else:
        return bw_translation_pipeline("treiñ eus ar galleg d'ar brezhoneg: " + text)[0]['translation_text']

# maximum number of interactions to keep in history
max_history_length = 3

# keep a hidden model "native" language chat history
native_chat_history = []

# example queries
example_queries = [{"text" : "Petra eo ar rekipe krampouezh ?"}, {"text": "Pelec'h emañ Pariz ?"}, {"text" : "Petra eo kêr vrasañ Breizh ?"}, {"text" : "Kont din ur farsadenn bugel ?"}]

with gr.Blocks(theme=gr.themes.Soft()) as demo:
    
    gr.Markdown("# BreizhBot\n## Breton Chatbot (Translation based)\nPart of the [GweLLM](https://github.com/blackccpie/GweLLM) project")
    
    chatbot = gr.Chatbot(
        label="Chat",
        placeholder="Degemer mat, petra a c'hellan ober evidoc'h ?",
        examples=example_queries,
        type="messages")
    msg = gr.Textbox(label='User Input')

    def clear(chat_history):
        """
        Handles clearing chat
        """
        chat_history.clear()
        native_chat_history.clear()

    chatbot.clear(clear, inputs=[chatbot])

    def example_input(evt: gr.SelectData):
        """
        Handles example input selection
        """
        return evt.value["text"]
    
    def user_input(message, chat_history):
        """
        Handles instant display of the user query (without waiting for model answer)
        """
        chat_history.append({"role": "user", "content": message})
        return chat_history

    def respond(message, chat_history):
        """
        Handles bot response generation
        """

        global native_chat_history

        fr_message = translate(message, forward=False)
        print(f"user fr -> {fr_message}")

        bot_fr_message = chat_engine.answer(fr_message, native_chat_history)
        print(f"bot fr -> {bot_fr_message}")
        bot_br_message = translate( bot_fr_message, forward=True)
        print(f"bot br -> {bot_br_message}")

        chat_history.append({"role": "assistant", "content": bot_br_message})

        native_chat_history.append({"role": "user", "content": fr_message})
        native_chat_history.append({"role": "assistant", "content": bot_fr_message})

        # limit the history length
        if len(chat_history) > max_history_length * 2:
            chat_history = chat_history[-max_history_length * 2:]
            native_chat_history = native_chat_history[-max_history_length * 2:]

        return "", chat_history

    chatbot.example_select(example_input, None, msg).then(user_input, [msg, chatbot], chatbot).then(respond, [msg, chatbot], [msg, chatbot])
        
    msg.submit(user_input, [msg, chatbot], chatbot).then(respond, [msg, chatbot], [msg, chatbot])

if __name__ == "__main__":
    demo.launch()