Spaces:
Running
Running
Commit
·
5fb65b7
1
Parent(s):
73b50ad
docker changes
Browse files- Dockerfile +23 -6
- app.py +128 -117
- requirements.txt +4 -1
- start.sh +36 -0
- test.py +16 -0
Dockerfile
CHANGED
|
@@ -1,16 +1,33 @@
|
|
| 1 |
# Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
|
| 2 |
# you will also find guides on how best to write your Dockerfile
|
| 3 |
|
| 4 |
-
FROM python:3.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
RUN useradd -m -u 1000 user
|
| 7 |
USER user
|
| 8 |
-
ENV
|
|
|
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
| 11 |
|
| 12 |
-
COPY --chown=user
|
| 13 |
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
-
COPY --chown=user . /app
|
| 16 |
-
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
|
|
|
| 1 |
# Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
|
| 2 |
# you will also find guides on how best to write your Dockerfile
|
| 3 |
|
| 4 |
+
FROM python:3.11-slim
|
| 5 |
+
|
| 6 |
+
RUN apt-get update && apt-get install -y curl && \
|
| 7 |
+
curl -fsSL https://ollama.ai/install.sh | sh && \
|
| 8 |
+
apt-get clean && rm -rf /var/lib/apt/lists/*
|
| 9 |
|
| 10 |
RUN useradd -m -u 1000 user
|
| 11 |
USER user
|
| 12 |
+
ENV HOME=/home/user \
|
| 13 |
+
PATH="/home/user/.local/bin:$PATH"
|
| 14 |
|
| 15 |
+
# Création des répertoires nécessaires
|
| 16 |
+
RUN mkdir -p $HOME/docker_ollama $HOME/logs
|
| 17 |
+
WORKDIR $HOME/docker_ollama
|
| 18 |
|
| 19 |
+
COPY --chown=user requirements.txt .
|
| 20 |
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 21 |
+
COPY --chown=user . .
|
| 22 |
+
RUN chmod +x start.sh
|
| 23 |
+
EXPOSE 7860 11434
|
| 24 |
+
|
| 25 |
+
CMD ["./start.sh"]
|
| 26 |
+
|
| 27 |
+
# WORKDIR /app
|
| 28 |
+
|
| 29 |
+
# COPY --chown=user ./requirements.txt requirements.txt
|
| 30 |
+
# RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 31 |
|
| 32 |
+
# COPY --chown=user . /app
|
| 33 |
+
# CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
app.py
CHANGED
|
@@ -1,125 +1,136 @@
|
|
| 1 |
from fastapi import FastAPI
|
| 2 |
import uvicorn
|
| 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 |
-
# self.model = model
|
| 63 |
-
|
| 64 |
-
# def classify_txn_type(self, state: AgentState) -> AgentState:
|
| 65 |
-
# messages = state["messages"]
|
| 66 |
-
# if self.system:
|
| 67 |
-
# messages = [SystemMessage(content=self.system)] + messages
|
| 68 |
-
|
| 69 |
-
# message = self.model.invoke(messages)
|
| 70 |
-
# return {"messages": [message]}
|
| 71 |
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
-
|
| 86 |
-
# result = state["messages"][-1]
|
| 87 |
-
# client = pygsheets.authorize(service_account_file="serviceaccount.json")
|
| 88 |
-
# worksheet = client.open_by_url("https://docs.google.com/spreadsheets/d/1t4bOM4fULdaVsjDDnqEG1g8Zey6M00UuFhTZC03_4xo")
|
| 89 |
-
# wk = worksheet[0]
|
| 90 |
-
# # Get number of rows in the worksheet
|
| 91 |
-
# df = wk.get_as_df(start='A1', end='G999')
|
| 92 |
-
# nrows = df.shape[0]
|
| 93 |
-
# wk.update_value(f'A{nrows+2}', result.amount)
|
| 94 |
-
# wk.update_value(f'B{nrows+2}', result.dr_or_cr)
|
| 95 |
-
# wk.update_value(f'C{nrows+2}', result.receiver)
|
| 96 |
-
# wk.update_value(f'D{nrows+2}', result.category)
|
| 97 |
-
# wk.update_value(f'E{nrows+2}', result.transaction_date)
|
| 98 |
-
# wk.update_value(f'F{nrows+2}', result.transaction_origin)
|
| 99 |
-
# wk.update_value(f'G{nrows+2}', state["messages"][0].content)
|
| 100 |
-
# return {"messages": ["Transaction Completed"]}
|
| 101 |
-
|
| 102 |
-
# def check_txn_and_decide(self, state: AgentState):
|
| 103 |
-
# try:
|
| 104 |
-
# result = json.loads(state['messages'][-1].content)['classification']
|
| 105 |
-
# except json.JSONDecodeError:
|
| 106 |
-
# result = state['messages'][-1].content.strip()
|
| 107 |
-
|
| 108 |
-
# return result == "Transaction"
|
| 109 |
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
# model = ChatGroq(temperature=1, groq_api_key=GROQ_API_KEY, model_name=MODEL)
|
| 119 |
-
# # model = ChatOllama(model="gemma3:4b", temperature=1, callback=OpikTracer())
|
| 120 |
|
| 121 |
-
|
|
|
|
|
|
|
| 122 |
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from fastapi import FastAPI
|
| 2 |
import uvicorn
|
| 3 |
+
from langchain_core.prompts import ChatPromptTemplate
|
| 4 |
+
from pydantic import BaseModel, Field
|
| 5 |
+
import pygsheets
|
| 6 |
+
import json
|
| 7 |
+
from langgraph.graph import StateGraph, END
|
| 8 |
+
from typing import TypedDict, Annotated
|
| 9 |
+
import operator
|
| 10 |
+
from langchain_core.messages import SystemMessage, HumanMessage, AnyMessage
|
| 11 |
+
from langchain_ollama import ChatOllama
|
| 12 |
+
from langgraph.pregel import RetryPolicy
|
| 13 |
+
import json
|
| 14 |
+
import pandas as pd
|
| 15 |
+
from google.oauth2 import service_account
|
| 16 |
+
import os
|
| 17 |
+
|
| 18 |
+
# GOOGLESHEETS_CREDENTIALS = json.dumps({"type": "service_account","project_id": "spendstracker-457904","private_key_id": "91bb3866226ab9f6734aa3fcc861faf17897d79d","private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCy2v9irZ+/f+hF\nGUW/ikqnQUGMTapLulH3I6+vdDoQBtFa3tNc5BcK991Qbbk8NG2Iv6Ni7H/dY4jv\nWlBr//WTcThKSa23HzjztDxFtCbw5BsaNcXzt3HlAb/ldZNjZkt8CJdzLDpDuiLc\n9PbJEUxNZZYZcGrY7rhse1Z5QCn/gX1GlTCqMORPoEcrCmjklabjht4le9SoUaCA\n9qABNt8SXaTPw1l4HxxxtMEQE466COxWn89lEDh+DqDjU+oXVwXUFscDUSrKtDFt\nNNjIy0yMlKTtLwtMaHMK6DdT+hqAjs4xaOFF2YQFDPLuXAX1PaLEi7J/ircese1s\nlQAcxrThAgMBAAECggEAAIvnQl2t8oeZRdbHLgfl5P9vzBYzqkISPItVHtff0os2\nygyKwEqpIF00BaokKgEuAYA2Z1e6J0rF0RdpTf8s+KucpKt3dqsHgUUgdwUPJmbI\nB2s5JN6/YBgChli239Og8OrUzaMJtYnE0ACGnYQqQ8VG8WJ0zR9jnF8/GyU9S5zQ\nGlUO04y6ftetQCaFaVIxxy9B/pOtSuIZi4qoJjGuOebMAcYWusrAWID3uewhsZJW\nqCQUMLyADK5ujEAybo7dpohph6YYwV/6bmCl/8rfnBiXn8NsuFfE9m/B7W9TBXku\n0AB/EF8rnjI2kEMXgUogLUj1DBm4pkVEpce+vd2LzQKBgQD7UJg35cLFCcjylumP\n/5f7d4V25ryWpfHMYSs9zefkRDnVrmwumanHy+IOSLgOMUC5dIcJOjQPutaUnKN5\nH4oW2q4K6Pmp4vlDeTNp9bHaZMokuQPVhMZvsWWcpFe3v6nMHA3tvshiWKiPVApo\nHaaXeNETateCpwGBn+9Eu5VAtQKBgQC2MJbQ/85DndSnk3YZ+aEtp2fEJABJwfPl\nM6vRnKy5gHKMPk1BZLb+B4osr+OA6eZEzp6VL2kOpI+lIZ9E20uMWOOzZUk+du6i\nEpXimHSoNPS56pksfS3tWoHRuyM9nm+rPEV0LPWotyenEfhtGE1CYZwnef1aMNfW\nKhui8uH6/QKBgQCLvoMGAhLNseU1T8lMMxn10L48IY2YT2om9Zkv4sEhYvat5TFu\nsC+CU9K9kp4V9jlBZpR4Aw9T99a+CGO2RF1q2+qPUoERgI6OgGSgdOiSwhzNUrvZ\nDN2y2ffgpFnKaR8nyinMm5udZCNGn7qxrlsmOx43J9/yXJ8vzxkjJROXSQKBgGsW\n4G91DU7dZPQjT1YxTzZAolO+PZUdNjlRR/trtnNLNwmMTWjUxGNJF0TxFi7eTYXA\nVaKnPX9n5y9PNgkJRbz3OtBmBsl6qwYFGqkYp+l/RyJI7UQjSG2tt4UKFMrRaB4k\nzUZebv9+uQYRIA8wK6mLKnhh0jPDZfrywU/kqEQZAoGAbywkV/FjFeAhmqY/yLQo\nho3E5T5jEc45kDadsK2OHVnCRb0tWh6VTdr93XQ9z5mygub7Wu16jp/FnHtA7f+E\no743SU8sYHxPGbVavlM/iRzbzhaF8o5lTHqqzLqrPvMOBbUpP/cRXugoxt7m7o4v\nvcRikUgNG7O8ipxnN28L8dg=\n-----END PRIVATE KEY-----\n","client_email": "spendstracker@spendstracker-457904.iam.gserviceaccount.com","client_id": "117285083911847446748","auth_uri": "https://accounts.google.com/o/oauth2/auth","token_uri": "https://oauth2.googleapis.com/token","auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/spendstracker%40spendstracker-457904.iam.gserviceaccount.com","universe_domain": "googleapis.com"})
|
| 19 |
+
sheet_url = "https://docs.google.com/spreadsheets/d/1t4bOM4fULdaVsjDDnqEG1g8Zey6M00UuFhTZC03_4xo/edit?gid=0#gid=0"
|
| 20 |
+
GOOGLESHEETS_CREDENTIALS = os.getenv("GOOGLESHEETS_CREDENTIALS")
|
| 21 |
+
|
| 22 |
+
class TransactionParser(BaseModel):
|
| 23 |
+
"""This Pydantic class is used to parse the transaction message."""
|
| 24 |
+
|
| 25 |
+
amount: str = Field(description="The amount of the transaction in decimal format. If the transaction is a credit or a reversal, then include negative sign. DO not insert currency.", example="123.45")
|
| 26 |
+
dr_or_cr: str = Field(description="Identify if the transaction was debit (spent) or credit (received). Strictly choose one of the values - Debit or Credit")
|
| 27 |
+
receiver: str = Field(description="The recipient of the transaction. Identify the Merchant Name from the value.")
|
| 28 |
+
category: str = Field(description="The category of the transaction. The category of the transaction is linked to the Merchant Name. Strictly choose from one the of values - Shopping,EMI,Education,Miscellaneous,Grocery,Utility,House Help,Travel,Transport")
|
| 29 |
+
transaction_date: str = Field(description="The date of the transaction in yyyy-mm-dd format. If the year is not provided then use current year.")
|
| 30 |
+
transaction_origin: str = Field(description="The origin of the transaction. Provide the card or account number as well.")
|
| 31 |
+
|
| 32 |
+
class AgentState(TypedDict):
|
| 33 |
+
messages: Annotated[list[AnyMessage], operator.add]
|
| 34 |
+
|
| 35 |
+
class Agent:
|
| 36 |
+
def __init__(self, model, system=""):
|
| 37 |
+
self.system = system
|
| 38 |
+
graph = StateGraph(AgentState)
|
| 39 |
+
graph.add_node("classify_txn_type", self.classify_txn_type)
|
| 40 |
+
graph.add_node("parse_message", self.parse_message)
|
| 41 |
+
graph.add_node("write_message", self.write_message)
|
| 42 |
+
graph.add_conditional_edges(
|
| 43 |
+
"classify_txn_type",
|
| 44 |
+
self.check_txn_and_decide,
|
| 45 |
+
{True: "parse_message", False: END}
|
| 46 |
+
)
|
| 47 |
+
graph.add_edge("parse_message", "write_message")
|
| 48 |
+
graph.add_edge("write_message", END)
|
| 49 |
+
graph.set_entry_point("classify_txn_type")
|
| 50 |
+
self.graph = graph.compile()
|
| 51 |
+
self.model = model
|
| 52 |
+
|
| 53 |
+
def classify_txn_type(self, state: AgentState) -> AgentState:
|
| 54 |
+
print("Classifying transaction type...")
|
| 55 |
+
messages = state["messages"]
|
| 56 |
+
if self.system:
|
| 57 |
+
messages = [SystemMessage(content=self.system)] + messages
|
| 58 |
+
|
| 59 |
+
message = self.model.invoke(messages)
|
| 60 |
+
print("Classifying transaction type completed.")
|
| 61 |
+
return {"messages": [message]}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
+
def parse_message(self, state: AgentState) -> AgentState:
|
| 64 |
+
print("Parsing transaction message...")
|
| 65 |
+
message = state["messages"][0]#.content
|
| 66 |
+
system = """
|
| 67 |
+
You are a helpful assistant skilled at parsing transaction messages and providing structured responses.
|
| 68 |
+
"""
|
| 69 |
+
human = "Categorize the transaction message and provide the output in a structed format: {topic}"
|
| 70 |
+
|
| 71 |
+
prompt = ChatPromptTemplate.from_messages([("system", system), ("human", human)])
|
| 72 |
+
chain = prompt | self.model.with_structured_output(TransactionParser)
|
| 73 |
+
result = chain.invoke({"topic": message})
|
| 74 |
+
print("Parsing transaction message completed.")
|
| 75 |
+
return {"messages": [result]}
|
| 76 |
+
|
| 77 |
+
def write_message(self, state: AgentState) -> AgentState:
|
| 78 |
+
print("Writing transaction message to Google Sheets...")
|
| 79 |
+
result = state["messages"][-1]
|
| 80 |
+
SCOPES = ('https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive')
|
| 81 |
+
service_account_info = json.loads(GOOGLESHEETS_CREDENTIALS)
|
| 82 |
+
my_credentials = service_account.Credentials.from_service_account_info(service_account_info, scopes=SCOPES)
|
| 83 |
+
client = pygsheets.authorize(custom_credentials=my_credentials)
|
| 84 |
+
# client = pygsheets.authorize(service_account_json=GOOGLESHEETS_CREDENTIALS)
|
| 85 |
+
# client = pygsheets.authorize(service_account_file="serviceaccount.json")
|
| 86 |
+
worksheet = client.open_by_url(sheet_url)
|
| 87 |
+
wk = worksheet[0]
|
| 88 |
+
# Get number of rows in the worksheet
|
| 89 |
+
df = wk.get_as_df(start='A1', end='G999')
|
| 90 |
+
nrows = df.shape[0]
|
| 91 |
+
wk.update_value(f'A{nrows+2}', result.amount)
|
| 92 |
+
wk.update_value(f'B{nrows+2}', result.dr_or_cr)
|
| 93 |
+
wk.update_value(f'C{nrows+2}', result.receiver)
|
| 94 |
+
wk.update_value(f'D{nrows+2}', result.category)
|
| 95 |
+
wk.update_value(f'E{nrows+2}', result.transaction_date)
|
| 96 |
+
wk.update_value(f'F{nrows+2}', result.transaction_origin)
|
| 97 |
+
wk.update_value(f'G{nrows+2}', state["messages"][0])
|
| 98 |
+
print("Writing transaction message to Google Sheets completed.")
|
| 99 |
+
return {"messages": ["Transaction Completed"]}
|
| 100 |
|
| 101 |
+
def check_txn_and_decide(self, state: AgentState):
|
| 102 |
+
try:
|
| 103 |
+
result = json.loads(state['messages'][-1].content)['classification']
|
| 104 |
+
except json.JSONDecodeError:
|
| 105 |
+
result = state['messages'][-1].content.strip()
|
| 106 |
|
| 107 |
+
return result == "Transaction"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
+
prompt = """You are a smart assistant adept at classifying different messages. \
|
| 110 |
+
You will be penalized heavily for incorrect classification. \
|
| 111 |
+
Your task is to classify the message into one of the following categories: \
|
| 112 |
+
Transaction, OTP, Promotional, Scheduled. \
|
| 113 |
+
Output the classification in a structured format like below. \
|
| 114 |
+
{"classification": "OTP"} \
|
| 115 |
+
"""
|
| 116 |
+
app = FastAPI()
|
|
|
|
|
|
|
| 117 |
|
| 118 |
+
@app.get("/")
|
| 119 |
+
def greetings():
|
| 120 |
+
return {"message": "Hello, this is a transaction bot. Please send a POST request to /write_message with the transaction data."}
|
| 121 |
|
| 122 |
+
@app.post("/write_message")
|
| 123 |
+
def write_message(data: dict):
|
| 124 |
+
message = data['message']
|
| 125 |
+
model = ChatOllama(model="gemma3:4b", temperature=1)
|
| 126 |
+
transaction_bot = Agent(model, system=prompt)
|
| 127 |
+
result = transaction_bot.graph.invoke({"messages": [message]})
|
| 128 |
+
return {"message": "Transaction completed successfully"}
|
| 129 |
+
|
| 130 |
+
@app.get("/ask")
|
| 131 |
+
def ask(prompt: str):
|
| 132 |
+
model = ChatOllama(model="gemma3:4b", temperature=1)
|
| 133 |
+
return model.invoke(prompt)
|
| 134 |
+
|
| 135 |
+
if __name__ == "__main__":
|
| 136 |
+
uvicorn.run(app, host="0.0.0.0", port=7860, log_level="info")
|
requirements.txt
CHANGED
|
@@ -1,2 +1,5 @@
|
|
| 1 |
fastapi
|
| 2 |
-
uvicorn[standard]
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
fastapi
|
| 2 |
+
uvicorn[standard]
|
| 3 |
+
langchain-ollama
|
| 4 |
+
langgraph
|
| 5 |
+
pygsheets
|
start.sh
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
#MisterAI/Docker_Ollama
|
| 3 |
+
#start.sh_01
|
| 4 |
+
#https://huggingface.co/spaces/MisterAI/Docker_Ollama/
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
# Set environment variables for optimization HFSpace Free 2CPU - 16GbRAM
|
| 8 |
+
export OMP_NUM_THREADS=2
|
| 9 |
+
export MKL_NUM_THREADS=2
|
| 10 |
+
export CUDA_VISIBLE_DEVICES=-1
|
| 11 |
+
|
| 12 |
+
# Start Ollama in the background
|
| 13 |
+
ollama serve &
|
| 14 |
+
|
| 15 |
+
# Pull the model if not already present
|
| 16 |
+
echo "Mistral 7b will be download"
|
| 17 |
+
if ! ollama list | grep -q "gemma3:4b"; then
|
| 18 |
+
ollama pull gemma3:4b
|
| 19 |
+
fi
|
| 20 |
+
|
| 21 |
+
# Wait for Ollama to start up
|
| 22 |
+
max_attempts=30
|
| 23 |
+
attempt=0
|
| 24 |
+
while ! curl -s http://localhost:11434/api/tags >/dev/null; do
|
| 25 |
+
sleep 1
|
| 26 |
+
attempt=$((attempt + 1))
|
| 27 |
+
if [ $attempt -eq $max_attempts ]; then
|
| 28 |
+
echo "Ollama failed to start within 30 seconds. Exiting."
|
| 29 |
+
exit 1
|
| 30 |
+
fi
|
| 31 |
+
done
|
| 32 |
+
|
| 33 |
+
echo "Ollama is Ready - Mistral 7b is Loaded"
|
| 34 |
+
|
| 35 |
+
# Démarrer Application
|
| 36 |
+
python app.py
|
test.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
from google.oauth2 import service_account
|
| 3 |
+
import pygsheets
|
| 4 |
+
|
| 5 |
+
GOOGLESHEETS_CREDENTIALS = json.dumps({"type": "service_account","project_id": "spendstracker-457904","private_key_id": "91bb3866226ab9f6734aa3fcc861faf17897d79d","private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCy2v9irZ+/f+hF\nGUW/ikqnQUGMTapLulH3I6+vdDoQBtFa3tNc5BcK991Qbbk8NG2Iv6Ni7H/dY4jv\nWlBr//WTcThKSa23HzjztDxFtCbw5BsaNcXzt3HlAb/ldZNjZkt8CJdzLDpDuiLc\n9PbJEUxNZZYZcGrY7rhse1Z5QCn/gX1GlTCqMORPoEcrCmjklabjht4le9SoUaCA\n9qABNt8SXaTPw1l4HxxxtMEQE466COxWn89lEDh+DqDjU+oXVwXUFscDUSrKtDFt\nNNjIy0yMlKTtLwtMaHMK6DdT+hqAjs4xaOFF2YQFDPLuXAX1PaLEi7J/ircese1s\nlQAcxrThAgMBAAECggEAAIvnQl2t8oeZRdbHLgfl5P9vzBYzqkISPItVHtff0os2\nygyKwEqpIF00BaokKgEuAYA2Z1e6J0rF0RdpTf8s+KucpKt3dqsHgUUgdwUPJmbI\nB2s5JN6/YBgChli239Og8OrUzaMJtYnE0ACGnYQqQ8VG8WJ0zR9jnF8/GyU9S5zQ\nGlUO04y6ftetQCaFaVIxxy9B/pOtSuIZi4qoJjGuOebMAcYWusrAWID3uewhsZJW\nqCQUMLyADK5ujEAybo7dpohph6YYwV/6bmCl/8rfnBiXn8NsuFfE9m/B7W9TBXku\n0AB/EF8rnjI2kEMXgUogLUj1DBm4pkVEpce+vd2LzQKBgQD7UJg35cLFCcjylumP\n/5f7d4V25ryWpfHMYSs9zefkRDnVrmwumanHy+IOSLgOMUC5dIcJOjQPutaUnKN5\nH4oW2q4K6Pmp4vlDeTNp9bHaZMokuQPVhMZvsWWcpFe3v6nMHA3tvshiWKiPVApo\nHaaXeNETateCpwGBn+9Eu5VAtQKBgQC2MJbQ/85DndSnk3YZ+aEtp2fEJABJwfPl\nM6vRnKy5gHKMPk1BZLb+B4osr+OA6eZEzp6VL2kOpI+lIZ9E20uMWOOzZUk+du6i\nEpXimHSoNPS56pksfS3tWoHRuyM9nm+rPEV0LPWotyenEfhtGE1CYZwnef1aMNfW\nKhui8uH6/QKBgQCLvoMGAhLNseU1T8lMMxn10L48IY2YT2om9Zkv4sEhYvat5TFu\nsC+CU9K9kp4V9jlBZpR4Aw9T99a+CGO2RF1q2+qPUoERgI6OgGSgdOiSwhzNUrvZ\nDN2y2ffgpFnKaR8nyinMm5udZCNGn7qxrlsmOx43J9/yXJ8vzxkjJROXSQKBgGsW\n4G91DU7dZPQjT1YxTzZAolO+PZUdNjlRR/trtnNLNwmMTWjUxGNJF0TxFi7eTYXA\nVaKnPX9n5y9PNgkJRbz3OtBmBsl6qwYFGqkYp+l/RyJI7UQjSG2tt4UKFMrRaB4k\nzUZebv9+uQYRIA8wK6mLKnhh0jPDZfrywU/kqEQZAoGAbywkV/FjFeAhmqY/yLQo\nho3E5T5jEc45kDadsK2OHVnCRb0tWh6VTdr93XQ9z5mygub7Wu16jp/FnHtA7f+E\no743SU8sYHxPGbVavlM/iRzbzhaF8o5lTHqqzLqrPvMOBbUpP/cRXugoxt7m7o4v\nvcRikUgNG7O8ipxnN28L8dg=\n-----END PRIVATE KEY-----\n","client_email": "spendstracker@spendstracker-457904.iam.gserviceaccount.com","client_id": "117285083911847446748","auth_uri": "https://accounts.google.com/o/oauth2/auth","token_uri": "https://oauth2.googleapis.com/token","auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/spendstracker%40spendstracker-457904.iam.gserviceaccount.com","universe_domain": "googleapis.com"})
|
| 6 |
+
sheet_url = "https://docs.google.com/spreadsheets/d/1t4bOM4fULdaVsjDDnqEG1g8Zey6M00UuFhTZC03_4xo/edit?gid=0#gid=0"
|
| 7 |
+
|
| 8 |
+
SCOPES = ('https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive')
|
| 9 |
+
service_account_info = json.loads(GOOGLESHEETS_CREDENTIALS)
|
| 10 |
+
my_credentials = service_account.Credentials.from_service_account_info(service_account_info, scopes=SCOPES)
|
| 11 |
+
client = pygsheets.authorize(custom_credentials=my_credentials)
|
| 12 |
+
|
| 13 |
+
print("Writing transaction message to Google Sheets...")
|
| 14 |
+
worksheet = client.open_by_url(sheet_url)
|
| 15 |
+
|
| 16 |
+
print(worksheet)
|