From adf114b82e7192e044395612220472116e96647b Mon Sep 17 00:00:00 2001
From: "Steve L. Nyemba" <steve.l.nyemba@vumc.org>
Date: Wed, 19 Mar 2025 20:38:40 +0000
Subject: [PATCH] Upload files to "www/html"

---
 www/html/demo.py  |  13 +++++
 www/html/medix.py | 138 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 151 insertions(+)
 create mode 100644 www/html/demo.py
 create mode 100644 www/html/medix.py

diff --git a/www/html/demo.py b/www/html/demo.py
new file mode 100644
index 0000000..e3e045a
--- /dev/null
+++ b/www/html/demo.py
@@ -0,0 +1,13 @@
+
+    import cms
+    #
+    # register this in config.plugins: {"demo":["info"]}
+
+
+    @cms.plugins(mimetype='application/json') :
+    def info (**_args):
+        _request= _args['request']
+        _config = _args['config']
+        return {"version":_config['system']['version'],'title':_config['layout']['header']['title']}
+        pass
+    
\ No newline at end of file
diff --git a/www/html/medix.py b/www/html/medix.py
new file mode 100644
index 0000000..2f19882
--- /dev/null
+++ b/www/html/medix.py
@@ -0,0 +1,138 @@
+from langchain_openai import AzureOpenAIEmbeddings, AzureOpenAI, AzureChatOpenAI
+from langchain_ollama import OllamaEmbeddings, OllamaLLM
+import io
+from langchain.chains import LLMChain
+from langchain_core.prompts import PromptTemplate
+import os
+import json
+import transport
+
+import cms
+import uuid
+from multiprocessing import Process 
+import pandas as pd
+import copy
+
+from gtts import gTTS
+import io
+import requests
+
+# USE_OPENAI = os.environ.get('USE_OPENAI',0)
+
+class ILLM :
+    def __init__(self,**_args) :
+        self.USE_OPENAI = 'openai' in _args
+        # self._args = _args['ollama'] if not self.USE_OPENAI else _args['openai']
+        _path = _args['ollama'] if not self.USE_OPENAI else _args['openai']
+        f = open(_path)
+        self._args = json.loads( f.read() )
+        f.close()
+        self._prompt = _args['prompt'] if 'prompt' in _args else {}
+    def embed(self,_question):
+        _pointer =  AzureOpenAIEmbeddings if self.USE_OPENAI else OllamaEmbeddings
+        _kwargs = self._args if 'embedding' not in self._args else self._args['embedding']
+        _handler = _pointer(**_kwargs)
+        return _handler.embed_query(_question)
+    def answer(self,_question,_context) :
+        _pointer =  AzureChatOpenAI if self.USE_OPENAI else OllamaLLM
+        _kwargs = self._args if 'completion' not in self._args else self._args['completion']
+        _llm =  _pointer(**_kwargs)
+        _prompt = PromptTemplate(**self._prompt)
+        chain   = LLMChain(llm=_llm,prompt=_prompt)
+        _input = {'context':_context,'question':_question}
+        _input = json.loads(json.dumps(_input))
+        resp = chain.invoke(_input)
+        return resp
+    def schema(self):
+        return 'openai' if self.USE_OPENAI else 'public'
+    def documents(self,_vector) :
+        _schema = 'openai' if self.USE_OPENAI else 'ollama'
+        pgr = transport.get.reader(label='llm', schema=_schema)
+        sql = f"""SELECT file, name, page, content, embeddings <-> '{json.dumps(_vector)}' similarity FROM {_schema}.documents
+        ORDER BY similarity ASC
+        LIMIT 5
+        """
+        _df = pgr.read(sql=sql)
+        pgr.close()
+
+        return _df
+    def lookup (self,index:int,token) :
+        _schema = 'openai' if self.USE_OPENAI else 'ollama'
+        pgr = transport.get.reader(label='llm', schema=_schema)
+        index = int(index)  + 1
+        _sql = f"SELECT * FROM (select row_number() over(partition by token) as row_index, answer from llm_logs where token='{token}') as _x where row_index    = {index}"
+        print (_sql)
+        _df = pgr.read(sql= _sql)
+        return _df.answer[0] if _df.shape[0] > 0 else None
+@cms.Plugin(mimetype="application/json",method="POST")
+def answer (**_args):
+    
+    _request = _args['request']
+    _config = _args['config']['system']['source']['llm']
+
+    _question = _request.json['question']
+    token = str(uuid.uuid4()) if 'token' not in _request.json else _request.json['token']
+    _index = _request.json['index'] if 'index' in _request.json else 0 
+
+    _llmproc = ILLM(**_config)
+
+    #
+    # Turn the question into a vector and send it to the LLM Server
+    #
+    _vector = _llmproc.embed(_question)
+    _df = _llmproc.documents(_vector)
+    _pages = _df.apply(lambda row: row.content,axis=1).tolist()
+    
+    #
+    # submit the request to the 
+
+
+    # return _df[['name','page','similarity']].to_dict(orient='records')
+    #
+    # Let us submit the question to the llm-server
+    #
+    resp =  _llmproc.answer(_question, _pages)
+    #
+    # @TODO :
+    #   - Log questions, answers and sources to see what things are like
+    _context = _args['config']['system']['context'].strip()
+    _out = {"token":token,"openai":_llmproc.USE_OPENAI,"answer":resp["text"],"documents": _df[["name","page"]].to_dict(orient='records')}
+    
+    
+    try:
+        def _logger():
+            _log = pd.DataFrame([dict(_out,**{'question':_question})])
+            _log.documents = _df[["name","page"]].to_json(orient='records')
+            pgw = transport.get.writer (label='llm',table='llm_logs')
+            pgw.write(_log)
+            pgw.close()
+        #
+        # send the thread 
+        pthread = Process(target=_logger)
+        pthread.start()
+    except Exception as e:
+        print (e)
+    # _out['stream'] = f'{_context}/api/medix/audio?token={token}&index={_index}'
+    return _out
+
+@cms.Plugin(mimetype="text/plain",method="POST")
+def info (**_args):
+    _config = _args['config']
+    return list(_config['system']['source']['llm'].keys())[0]
+@cms.Plugin(mimetype="audio/mpeg",method="GET")
+def audio (**_args):
+    _request = _args['request']
+    _config = _args['config']['system']['source']['llm']
+    _index = _request.args['index']
+    _token = _request.args['token']
+    _llmproc = ILLM(**_config)
+
+    _llmproc = ILLM(**_config)
+    _text = _llmproc.lookup(_index,_token)
+    g = gTTS(_text,lang='en')
+    return g.stream()
+    # stream = io.BytesIO()
+    # for line in g.stream() :
+    #     stream.write(line)
+    # stream.seek(0)
+    # return stream #g.stream()
\ No newline at end of file