Decorators in Open Event API Server

One of the interesting features of Python is the decorator. Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated.

Open Event API Server makes use of decorator in various ways. The ability to wrap a function and run the decorator(s) before executing that function solves various purpose in Python. Earlier before decoupling of Orga Server into API Server and Frontend, decorators were being used for routes, permissions, validations and more.

Now, The API Server mainly uses decorators for:

  • Permissions
  • Filtering on the basis of view_kwargs or injecting something into view_kwargs
  • Validations

We will discuss here first two because validations are simple and we are using them out of the box from marshmall-api

The second one is custom implementation made to ensure no separate generic helpers are called which can add additional database queries and call overheads in some scenarios.

Permissions Using Decorators

Flask-rest-jsonapi provides an easy way to add decorators to Resources. This is as easy as defining this into Resource class

  1. decorators = (some_decorator, )

On working to event role decorators to use here, I need to follow only these 3 rules

  • If the user is admin or super admin, he/she has full access to all event roles
  • Then check the user’s role for the given event
  • Returns the requested resource’s view if authorized unless returns Forbidden Error response.

One of the examples is:

def is_organizer(view, view_args, view_kwargs, *args, **kwargs):
  user = current_identity
 
  if user.is_staff:
      return view(*view_args, **view_kwargs)
 
  if not user.is_organizer(kwargs['event_id']):
      return ForbiddenError({'source': ''}, 'Organizer access is required').respond()
 
  return view(*view_args, **view_kwargs)

From above example, it is clear that it is following those three guidelines

Filtering on the basis of view_kwargs or injecting something into view_kwargs

This is the main point to discuss, starting from a simple scenario where we have to show different events list for different users. Before decoupling API server, we had two different routes, one served the public events listing on the basis of event identifier and other to show events to the event admins and managers, listing only their own events to their panel.

In API server there are no two different routes for this. We manage this with a single route and served both cases using the decorator. This below is the magic decorator function for this purpose

def accessible_role_based_events(view, view_args, view_kwargs, *args, **kwargs):
  if 'POST' in request.method or 'withRole' in request.args:
      _jwt_required(app.config['JWT_DEFAULT_REALM'])
      user = current_identity
      if 'GET' in request.method and user.is_staff:
          return view(*view_args, **view_kwargs)
      view_kwargs['user_id'] = user.id
  return view(*view_args, **view_kwargs)

It works simply by looking for ‘withRole’ in requests and make a decision to include user_idinto kwargs as per these rules

  1. If the request is POST then it has to be associated with some user so add the user_id
  2. If the request is GET and ‘withRole’ GET parameter is present in URL then yes add the user_id. This way user is asking to list the events in which I have some admin or manager role
  3. If the request is GET and ‘withRole’ is defined but the logged in user is admin or super_adminthen there is no need add user_id since staff can see all events in admin panel
  4. The last one is GET and no ‘withRole’ parameter is defined therefore ignores and continues the same request to list all events.

The next work is of query method of EventList Resource

if view_kwargs.get('user_id'):
          if 'GET' in request.method:
              query_ = query_.join(Event.roles).filter_by(user_id=view_kwargs['user_id']) \
                  .join(UsersEventsRoles.role).filter(Role.name != ATTENDEE)

This query joins the UsersEventsRoles model whenever user_id is defined. Thus giving role-based events only.

The next interesting part is the Implementation of permission manager to ensure permission decorators doesn’t break at any point. We will see it in next post.

References:

https://wiki.python.org/moin/PythonDecorators

Continue ReadingDecorators in Open Event API Server

Relationships and its usage in Open Event Orga Server

JSON API is a specification for writing RESTFul APIs (CRUD interfaces). This specification basically sets the standard for a client to request the resources and how a server is supposed to response minimizing the redundancy and number of requests.

If we look at the general implementation of RESTful APIs, we see that we are working on creating every endpoint manually, there are no relations. Sometimes different endpoints are being created for some slightly different business logic than other. We solve this purpose specifically the relationships using JSON API spec.

Features of JSON API

Apart from CRUD interface, JSON-API-Spec provides

  • Fetching Resources
  • Fetching Relationships
  • Inclusion of Related Resources
  • Sparse Fieldsets
  • Sorting
  • Pagination
  • Filtering

For Open Event API Server we need these below

  • Proper relationship definitions
  • Sorting
  • Filtering
  • Pagination

So JSON-API spec is a good choice for us at Orga Server since it solves our every basic need.

Overview of Changes

Firstly the main task was shifting to the library flask-rest-jsonapi because this library stands to our four needs in API. The changes included:

  • ensuring JSON-API spec in our requests and responses (although the most of the work is done by the library)
  • Reusing the current implementation of JWT authorization.
  • To locate the new API to /v1. Since Orga server is going to be API server with Open Event system following the API-centric approach, therefore, there is no need to have /api/v1
  • Now out timestamps in response and request will be timezone aware thus following ISO 8601 with timezone information (Eg. 2017-05-22T09:12:44+00:00)

Media type to use: application/vnd.api+json

A Relationship in JSON API

To begin with APIs, I started working on Sessions API of Orga server and the relation of a session with the event was represented as one of the attribute of Schema of the Session API like this below,

event = Relationship(attribute='event',
                        self_view='v1.session_event',
                        self_view_kwargs={'id': '<id>'},
                        related_view='v1.event_detail',
                        related_view_kwargs={'session_id': '<id>'},
                        schema='EventSchema',
                        type_='event')


  • attribute: name of the attribute with which this will be referenced in response API
  • self_view: A view name which represents the view of this relationship. This is a relationship endpoint of sessions API.
  • self_view_kwargs: view_kwargs for self_view, this is used to provide ID of the specific record to the relationship endpoint.
  • related_view: An endpoints to the related API/Object. Here the related object is ‘event’ so I have provided the endpoint to get the event detail.
  • related_view_kwargs: Here we can provide kwargs to the related object’s endpoint. Here we are sending the value of <Session_id> URL parameter on the related endpoint by mapping it with “id” of the current session object.
  • Schema: this is the schema of the related object. Since we have related object is event, therefore, added EventSchema of it.
  • type_: this is the type of related object which is event here.

After defining them, the magic here is no need to define and inject the relationship endpoints in the responses. We just need to add one route to v1.event_detail and we have relationship ready.

To make this work, I added these on routes file:

  • ‘/sessions/<int:session_id>/event’ to the v1.event_detail
  • api.route(SessionRelationship, ‘session_event’,
             ‘/sessions/<int:id>/relationships/event’)

And we have Relationship ready as Session -> Event in the API ready. We can use these relationships to Get the relationship Object(s), Updated them or Delete them. This helps Orga Server is a very efficient scale since many of our endpoints are related with events directly so instead of separately defining relationships we are able to do this with the help of JSON API and flask-rest-jsonapi

An Example Response

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "data": {
    "relationships": {
      "event": {
        "links": {
          "self": "/v1/speakers-calls/3/relationships/event",
          "related": "/v1/speakers-calls/3/event"
        }
      }
    },
    "attributes": {
      "announcement": "Google",
      "ends-at": "2023-05-30T09:30:10+00:00",
      "hash": null,
      "starts-at": "2022-05-30T09:30:10+00:00",
      "privacy": "public"
    },
    "type": "speakers-call",
    "id": "3",
    "links": {
      "self": "/v1/speakers-calls/3"
    }
  },
  "jsonapi": {
    "version": "1.0"
  },
  "links": {
    "self": "/v1/speakers-calls/3"
  }
}

Above example shows the relationships in the response object. We can directly check in the application using these APIs that to which type of objects this object is related with and endpoints to get related data.

Next steps in the implementation are Docs for APIs, permissions implementations to secure the endpoints and setting up unit testing of the endpoints which will be discussed in next posts.

Continue ReadingRelationships and its usage in Open Event Orga Server

Open Event Server: Dealing with environment variables

FOSSASIA‘s Open Event Server uses some environment variables to maintain different configuration for different deployment. However one con of it was, for local development, developers have to run many export commands.

It all started with the “It is not convenient, we humans are lazy.” phrase. A recent suggestion was to read this environment variables with files rather than running commands every time.
This few example environment variable commands were:

export DATABASE_URL=postgresql://open_event_user:test@127.0.0.1:5432/test

and

export INTEGRATE_SOCKETIO=false

 

Open Event Server now uses .env file and envparse to handle this.

The changes were:

  1. We store the variables in .env file, let it get ignored by git, and
  2. Use envparse to parse the file.

What is envpase:
       envparse is a simple utility to parse environment variables. It aims to eliminate duplicated, often inconsistent parsing code and instead provide a single, easy-to-use wrapper.

So instead of reading the string from the command line everytime:

export DATABASE_URL=postgresql://open_event_user:password@127.0.0.1:5432/open_event_db

We read it from the file:

To read from command line we had:

SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL', None)

Which now was parsed using envparse as:

SQLALCHEMY_DATABASE_URI =  env('DATABASE_URL', default=None)

In the above example, DATABASE_URL is a string and we store this string in SQLALCHEMY, setting the default by the default parameter(None in this case).

The type of environment variable is originally string, we can simply use env to parse these strings. For simplicity and understanding we can also use env.str. For different types, we can simply type cast them like env.bool (for boolean), env.int (for integer) etc. One good advantage of this envparse feature is the direct use of these type cast rather than checking for strings (i.e. reading the string from command line).

For example, earlier we had something like this:

socketio_integration = os.environ.get('INTEGRATE_SOCKETIO’)
if socketio_integration == true’:
INTEGRATE_SOCKETIO =True

Using envparse, we can have something like this:

INTEGRATE_SOCKETIO = env.bool('INTEGRATE_SOCKETIO’, default=False)

This helps in parsing as boolean instead of string. So, if we have INTEGRATE_SOCKETIO=true in .env file, we can write INTEGRATE_SOCKETIO = env.bool(‘INTEGRATE_SOCKETIO’, default=False). This automatically converts the true to boolean True in python.

In order to use envparse we install envparse with:

$ pip install envparse


In the case of
Open Event Server project, you only have to install the requirements.txt and copy the .env.example already mentioned in installation doc.

This is how we finally remove the headache of writing big exports again and again and fairly helps beginners to start off with Open Event Server  project much more easily and quickly.

Continue ReadingOpen Event Server: Dealing with environment variables

Permission Dependent Schema for Admin Settings in Open Event Server

For implementing the next version of the API in Open Event, the schema is a very important thing. It tells you exactly what all information you need to send in the body and how the response will look. In flask-rest-jsonapi, we usually mention a schema for an API which is then used for validating requests and sending response. Using decorators, we restrict who all can create, edit or get responses from a particular API endpoint. However, a scenario may so arise that you need to show data to users at different permissions level, but the amount of data shown significantly varies with the permission.

For example, for the settings API in our case. There are few informations like the app name, app tagline that we want to be available to users at all permission levels. However, informations such as aws secret key, or mailing secret keys or any other secret key, we want that to be available only to the admin and super admin. And the responses should be such that users at different permission level should feel that whatever information shown to them is complete and not missing.

So, what we do is we create different schemas, in our case 2 different schemas. Depending on the permission of the user, we show them a particular schema. In our case, the two schemas are SettingSchemaAdmin and SettingSchemaNonAdmin. In SettingSchemaAdmin, we have all the attributes or fields that are present and is accessible to the Admin and Super Admin. In the SettingSchemaNonAdmin however, we have only those fields and attributes that we want to show to all non admin users.

from flask_jwt import current_identity
 
class SettingDetail(ResourceDetail):
    """
    setting detail by id
    """
 
    def before_get(self, args, kwargs):
        kwargs['id'] = 1
        if current_identity.is_admin or current_identity.is_super_admin:
            self.schema = SettingSchemaAdmin
        else:
            self.schema = SettingSchemaNonAdmin

 

The above code helps us achieve this. If you have read previous blogs about the API server, you would already know that we are using JWT for authenticating our users. In this code, we are importing current_identity from flask_jwt. Current_identity, returns us an object of the User type which has properties such as is_admin, is_super_admin, etc. to help us identify the permission level of that user.
Using this object, we check whether the user who is making the request via jwt authentication is an admin or super admin, or just a normal registered user.

        if current_identity.is_admin or current_identity.is_super_admin:
            self.schema = SettingSchemaAdmin
        else:
            self.schema = SettingSchemaNonAdmin

 

So, if the current user sending the request is an admin, then we set the schema for the Resource manager class of the flask-rest-jsonapi as SettingSchemaAdmin, which we have already declared before containing all the fields, else, we set it as SettingSchemaNonAdmin which has limited number of attributes.

Continue ReadingPermission Dependent Schema for Admin Settings in Open Event Server

Preparing a release for Phimpme Android

Most of the essential features are now in a stable state in our Phimpme Android app. So we decided to release a beta version of the app. In FOSSASIA we follow branch policy where in development all current development will take place and in master branch the stable code resides.

Releasing an app is not just building an apk and submitting to the distribution platform, certain guidelines should follow.

How I prepare a released apk for Phimpme

List down the feature

We discussed on our public channel what features are now in stable state and can be released. Features such as account manager and Share Activity is excluded because it is not complete and in under development mode. We don’t want to show and under development feature. So excluded them. And made a list of available features in different category of Camera, Gallery and Share.

Follow the branch policy.

The releasable and stable codebase should be on master branch. It is good to follow the branch policy because it helps if we encounter any problem with the released apk. We can directly go to our master branch and check there. Development branch have very volatile because of active development going on.

Every Contributor’s contribution is important

When we browse our old branches such as master in case of ours. We see generally it is behind 100s of commits to the development. In case of that when we create a PR for that then it generally contains all the old commits to make the branch up to the latest.

In this case while opening and merging do not squash the commits.

Testing from Developer’s end

Testing is very essential part in development. Before releasing it is a good practice that Developer should test the app from their end. We tested app features in different devices with varying Android OS version and screen size.

  • If there is any compatibility issue, report it right away and there are several tools in Android to fix.
  • Support variety of devices and screen sizes

Changing package name, application ID

Package name, application ID are vitals of an app. Which uniquely identifies them as app in world. Like I changed the package name of Phimpme app to org.fossasia.phimpme. Check all the permission app required.

Create Release build type

Build types are great to way categorize the apps. Debug and Release are two. There are various things in codebase which we want only in Debug modes. So when we create Release mode it neglect that part of the code.

Add build types in you application build.gradle

buildTypes {
   release {
       minifyEnabled false
   }

Rebuild app again and verify from the left tab bar

Generate Signed apk and Create keystore (.jks) file

Navigate to Build → Generate Signed APK

Fill all details and proceed further to generate the signed apk in your home directory.

Adding Signing configurations in build.gradle

Copy the keystore (.jks) file to the root of the project and add signing configurations

signingConfigs {
       config {
           keyAlias 'phimpme'
           keyPassword 'phimpme'
           storeFile file('../org.fossasia.phimpme.jks')
           storePassword 'XXXXXXX'
       }
   }

InstallRelease Gradle task

Navigate to the right sidebar of Android Studio click on Gradle


Click on installRelease to install the released apk. It take all the credentials from the signing configurations.

Resources

Continue ReadingPreparing a release for Phimpme Android

Sentiment Data in Emoji-Heatmapper loklak App

Analysing emojis can uncover meaning and sentiment in ways regular text analytics cannot. So this was the main idea to introduce sentiment data into the Emoji-Heatmapper app. LokLak Search API has features such as classification and categorization of tweets. The emotions, for instance, can be joy, anticipation, sad etc.

So, in the Emoji-heatmapper app, I am displaying the occurrence of emojis on the map according to the location traced and also the sentiment related to the emoji i.e., search query as follows:

How to get the sentiment data:

One should simply enter the emoji into the search box for the results. The following code shows part of the LokLak Search API results (JSONObject):

      "hashtags_count": 0,
      "classifier_emotion": "anger",
      "classifier_emotion_probability": 
      1.2842921170985733E-9,
      "classifier_language": "english",
      "classifier_language_probability": 
      1.4594549568869297E-8,
      "without_l_len": 49,
      "without_lu_len": 49,
      "without_luh_len": 49,

I am using the above field name ”classifier_emotion” to display the results.

Till here getting the data relevant to query part is done. Next, the classifier_emotion of each tweet containing the query is collected into an array and sorted to get a unique list.

var emotion = [];
var emotions_array = [];

for (var i = 0; i  <  tweets.statuses.length; i++) {
    if (tweets.statuses[i].classifier_emotion) {
        emotion = tweets.statuses[i].classifier_emotion;
        emotions_array.push(emotion);
    }

    emotions_array.sort();
    emotion_array = jQuery.unique( emotions_array );

Loading the Sentiment data onto the Screen

When the query has a single emotion, or if multiple emotions or no emotions. These use cases/situations are displayed as follows:

Fig: Single Emotion

Fig: Multiple Emotions

Fig: No Emotions data

The code which creates the data dynamically on the output screen is as follows:

//Loading the sentiment
$(document).ready(function() {
    var listItems= "";
    if (emotions_array.length == 0) {
        listItems = "No Sentiment data is available for " + query
    }
    if (emotion_array.length == 1) {
        listItems += "<h3> Sentiment of " + query + " is ";
    } else if (emotion_array.length > 1) {
        listItems += "<h3> Sentiments of " + query + " are ";
    }

    var emotion_data = emotion_array.join(", ") + "."
    listItems += emotion_data + "</h3>"

    $("#sentiment").html(listItems);
});

Conclusion

The Emoji-Heatmapper app displays the sentiment data of the query being searched for which populates data dynamically using LokLak Search API.

Resources

Continue ReadingSentiment Data in Emoji-Heatmapper loklak App

Viewing an Event in Giggity

Giggity is an Android app that loads xCal, pentabarf, frab, wafer and iCal files (that contain schedules of conferences, festivals and other events) and lets you browse them in various convenient formats. It is a generic app that can be used for any event that publishes their schedule in an open format. Recently support to see Open Event JSON format has been added in the Giggity. In this blog I describe the simple steps you need to follow to see the event that is created in the Open Event server and can be seen in the Giggity app. Although the process of creating an event is quite detailed but the UI is very user friendly and simple to use so here I describe the process after creating the event and adding it in Giggity app

1. Go to your event dashboard

2. Click on the export button

3. Select sessions and microlocations by clicking the switch buttons. Get the url generated and copy it. Skipping the microlocations will disable the option to navigate to the location in map opening from the app.

4. Click on the “+” button on the toolbar and paste the link.

   

5. Now you can see the sessions with locations. Slide the navigation drawer to see the links and signup url or create the home screen shortcut.

   

So here you can see your event following these five simple steps. Watch this video to see this in action.

https://www.youtube.com/watch?v=RairLTXqqDI

Continue ReadingViewing an Event in Giggity

Differentiating between received file formats for Event Apps

Sometimes we need to operate on files of different formats in the same app itself for example Giggity app parses the file in iCal, xCal, pentabarf and now in Open Event JSON format.

It could be problematic as every format needs different type of manipulation to read and get the relevant data from it, for example the JSON format is based on objects and arrays in it from which we can get the data by referencing titles of the data while pentabarf XML identifies the elements with tags. Also it is not evident from the link itself which format is being received. So to see which type of file is received instead of analyzing the entire file we look for the few initials of the syntax from which it becomes evident.

I recently used this method to differentiate between the JSON and iCal format to display sessions of an event in the Giraffe app in Open Event JSON format which is also being used in Giggity.

Let’s have a look on how to actually implement this. It is simple after you get the data from the url. Instead of iterating for the entire data we read the initial data only to see what kind of file we have received.

BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
String line = r.readLine();

if(line.contains("BEGIN:VCALENDAR")) {
 SharedPreferences.Editor edit = prefs.edit();
 edit.putString("type", "ical");
 edit.commit();
 Log.e("Response type","ical");
} 
else if(line.contains("{")) {
 SharedPreferences.Editor edit = prefs.edit();
 edit.putString("type", "json");
 edit.commit();
 Log.e("Response type","json");
}

We saved the type of response received in the shared preferences so we retrieve it later from anywhere in the app to see what kind of data we have received instead of passing it in between functions or activities.

See this to check as you download the data from the URL asynchronously, so you don’t need to do it later or manipulations needs to be done asynchronously too.

So when you are checking in asynchronously using AsyncTask class get shared preferences in onPreExecute() and update it in doInBackground() as we download the data and check.

The other advantage of this method is that we can close the thread or return to the main activity if the file format found is not readable or not of desired format.

Continue ReadingDifferentiating between received file formats for Event Apps

Map Responses from SUSI Server

Giving user responses in Maps is a very common reply of various assistants. Android and iOS clients of SUSI.AI can Render their own custom map views but there is a challenge in doing that in Bots and other clients which can only render Images.

The MapServlet in SUSI-Server is a servlet that takes the constraints of a map as input parameters and returns PNG Image of the rendered map.

This is a simple HttpServlet. Since it does not requires any auth or user rights we do not extend AbstactAPIHandler in this class.

 
public class MapServlet extends HttpServlet {

This is to method which runs whenever the Servlet receives a GET Query. After getting the query the function call another function “process(…)” which processes the input parameters.

 
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse          response) throws ServletException, IOException {
Query post = RemoteAccess.evaluate(request);

This line is the for DDOS Protection.  It checks if the user query rate is too high and rate limit his queries. If Server suspects that the post is a DDOS then it returns a 503 error.

if (post.isDoS_blackout()) {
  response.sendError(503, "your request frequency is too high"); return;
} 
process(request, response, post);

The process method get the zoom, latitude, longitude, width and the height of the map and checks for the errors in them.

if (map.getHeight() > height || map.getWidth() > width) {
            BufferedImage bi = map.getImage();

            int xoff = (map.getWidth() - width) / 2;
            int yoff = (map.getHeight() - height) / 2;

            bi = bi.getSubimage(xoff, yoff, width, height);
            map = new RasterPlotter(width, height, RasterPlotter.DrawMode.MODE_REPLACE, "FFFFFF");
            map.insertBitmap(bi, 0, 0);
        }

Then we compute our image using RasterPlotter.

map.setDrawMode(DrawMode.MODE_SUB);
map.setColor(0xffffff);
if (text.length() > 0) PrintTool.print(map, 6, 12, 0, uppercase ? text.toUpperCase() : text, -1, false, 100);
PrintTool.print(map, map.getWidth() - 6, map.getHeight() - 6, 0, "MADE WITH LOKLAK.ORG", 1, false, 50);

Here we calculate the height of the map. If a user passed a height and width in get parameters, we scale the map according to that but if not its 256×256.

    int mx = (int) (map.getWidth() * (lon - west_lon) / (east_lon - west_lon));
    int my = (int) (map.getHeight() * (lat - north_lat) / (south_lat - north_lat));

// the marker has a height of 40 pixel and a width of 25 pixel
    final BufferedImage logo = ImageIO.read(FileSystems.getDefault().getPath("html").resolve("artwork").resolve("marker-red.png").toFile());
    map.insertBitmap(logo, Math.min(map.getWidth() - 25, Math.max(0, mx - 12)), Math.min(map.getHeight() - 40, Math.max(0, my - 40)), FilterMode.FILTER_ANTIALIASING);

We use the code below to set some text on the map for example the name of the place or the city etc.

map.setDrawMode(DrawMode.MODE_SUB);
map.setColor(0xffffff);
if (text.length() > 0) PrintTool.print(map, 6, 12, 0, uppercase ? text.toUpperCase() : text, -1, false, 100);
PrintTool.print(map, map.getWidth() - 6, map.getHeight() - 6, 0, "MADE WITH LOKLAK.ORG", 1, false, 50);

Finally we draw a marker on map

    int mx = (int) (map.getWidth() * (lon - west_lon) / (east_lon - west_lon));
    int my = (int) (map.getHeight() * (lat - north_lat) / (south_lat - north_lat));
      
    final BufferedImage logo = ImageIO.read(FileSystems.getDefault().getPath("html").resolve("artwork").resolve("marker-red.png").toFile());
    map.insertBitmap(logo, Math.min(map.getWidth() - 25, Math.max(0, mx - 12)), Math.min(map.getHeight() - 40, Math.max(0, my - 40)), FilterMode.FILTER_ANTIALIASING);

  At last we set the copyright message of OPENSTREETMAP at the bottom left.

PrintTool.print(map, 6, map.getHeight() - 6, 0, "(C) OPENSTREETMAP CONTRIBUTORS", -1, false, 100);

At the end we write the image and set the headers for Cross Origin Access.

    response.addHeader("Access-Control-Allow-Origin", "*");
        RemoteAccess.writeImage(fileType, response, post, map);
        post.finalize();
    }
}

 The servlet can be tested locally at

http://localhost:4000/vis/map.png?text=Test&mlat=1.28373&mlon=103.84379&zoom=18

Or on the live SUSI Server
http://api.susi.ai/vis/map.png?text=Test&mlat=1.28373&mlon=103.84379&zoom=18

Output:

References:

https://www.openstreetmap.org/

http://wiki.openstreetmap.org/wiki/Java_Access_Example

https://github.com/fossasia/susi_server/

Continue ReadingMap Responses from SUSI Server

Setting up Your Own Custom SUSI AI server

When you chat with any of the SUSI clients, all the requests are made to standard SUSI server. But let us say that you have implemented some features on server and want to test it. Simply launch your server and you get your own SUSI server. You can then change the option to use your own server on the SUSI Android and Web Chat client.

The first step to get your own copy of the SUSI server is browse to https://github.com/fossasia/susi_server and fork it. Clone your origin head to your local machine and make the changes that you want. There are various tutorials on how to add more servlets to SUSI server, how to add new parameters to an existing action type or maybe modification or a similar type of memory servlet.

To start coding, you can either use some IDE like IDEA by Intelij (download it from here) or open the files you want to modify in a text editor. To start the SUSI server via command line terminal (and not IDE) do the following:

 

Open the terminal in the project directory cloned. Now write in the following command (It is expected that you have your JAVA installed with JAVA_PATH variable setup):

./gradlew build

This will install all the project dependencies required for the support of the project. Next execute :

bin/start.sh

This will take a little time but you will soon see a popped up window in your default browser and the server will start. The landing page of the website will launch. Make the modifications in the server you were aiming. The server is up now. You can access it at local ip address here:

http://127.0.0.1/

But if you try to add this local address in the URL field of any client, it will not work and give you an error. To access this server using a client, open your terminal and execute

ipconfig	//if you are running a windows machine{not recommended}
ifconfig	//if you are running a linux machine{recommended for better performance}

 

This will give you a list of various IP. Find Wireless LAN adapter Wi-Fi. Copy the IPv4 IP address. This is the link you need to enter in the server URL field in the client (Do not forget to add http:// before your IP address). Now sign up and you will be good to go.

Additional Resources :

Continue ReadingSetting up Your Own Custom SUSI AI server